Tag: ssh keys

  • Creating passwordless logins with Ansible

    What kind of users? Well, a special user called Ansible, which will use SSH keys to login into remote devices, allowing for full automation on playbooks.

    Creating a new key

    If you have been following the series, maybe you remember that we already created keys on the Juniper Junos SSH Keys post.

    To create a new key, let’s issue the ssh-keygen command as follows. The -f flag tells the output path, and the -C flags specifies a comment.

    $ ssh-keygen -f ansible.key -C ansible-login-passwordless

    This should output two files, ansible.key and ansible.key.pub.

    The public key should look something like this.

    $ cat ansible.key.pub 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtJUPfzJY6vKqLUssPPQe+LD7qRmIPbVhb/1i4Qab7T0Vf3x+ItfJyV4Ej4FsnRSU8iMU8J5eIdcetGQfsmwIZAm8glB0T6En5F9lvq2Yd+3RKIvxM3UlrIH6EaRedhsRUyV96CHfIO2nVqS9dmFfgrOJMIOwfTWIiRDNczUPw7aqw0FExslw9ZC0FO/1A6hYgofkGLrdIu9gK/WkNg5BE1EUCYPqbDBEHnnhv3C33LqiSJZnXJyqu53qz+jlv+1LZxerNHuovMGZMkjQsBo2f3r9Gk/9HqBmT0rcLr5prm4CqqryJ3S9VyVVlF599BlqYMuMjj+fCj277R8kSnLxl ansible-login-passwordless

    Of course we need an inventory to use, which has the following content.

    $ cat inventory.yml 
    ---
    all:
      hosts:
        vars:
          ansible_ssh_user: ansible
          ansible_ssh_private_key_file: ansible.key
          ansible_python_interpreter: auto_silent
        hosts:
          localhost:
    

    This inventory only has one host, localhost, and uses three main variables:

    • ansible_ssh_user, which tell Ansible to use the user ansible
    • ansible_ssh_private_key_file, which indicates the key for this user
    • ansible_python_interpreter, just to avoid non needed logs

    The playbook will looks like this. Notice we don’t need to gather_facts here, and we will instruct ansible to use become to gain privileges on the destination host.

    ---
    - hosts: all
      become: yes
    
      tasks:
    
        - name: Make sure we have a "wheel" group
          group:
            name: wheel
            state: present
    
        - name: Allow 'wheel' group to have passwordless sudo
          lineinfile:
            dest: /etc/sudoers
            state: present
            regexp: '^%wheel'
            line: '%wheel ALL=(ALL) NOPASSWD: ALL'
            validate: 'visudo -cf %s'
            
        - name: Create "ansible" user
          user:
            name: ansible
            comment: Ansible Automation User
            groups: wheel
    
        - name: Add ssh key
          authorized_key:
            user: ansible
            state: present
            key: "{{ lookup('file', './ansible.key.pub') }}"
    

    First, we want to make sure there is a group called wheel which will group users with administrative privileges.

    Then, the /etc/sudoers file will be edited by allowing the wheel group to gain privileges, with a failsafe using a visudo validation.

    Once the group has been created, the new user will be created, and a SSH key will be added to it.

    It seems allright, but, how should we run the playbook, if the default user is ansible and this user does not exists yet? Let’s give it a try.

    $ ansible-playbook create-user.yml -i inventory.yml 
    
    PLAY [all] ************************************************************************
    
    TASK [Gathering Facts] ************************************************************
    fatal: [localhost]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ansible@localhost: Permission denied (publickey,password).", "unreachable": true}
    
    PLAY RECAP ************************************************************************
    localhost                  : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
    

    It fails, as expected, because the ansible user does not exists in the host.

    Well, there is a way to provide a one-time password by connecting a as different user. You will need to install sshpass with your favourite package manager, like apt install sshpass.

    One installed, run the playbook once again with the following arguments:

    • -e “ansible_ssh_user=xxxxx”, where xxxxx is a valid user on the remote host
    • -kK, which tell Ansible to ask for a login and a sudo password
    $ ansible-playbook create-user.yml -i inventory.yml -e "ansible_ssh_user=arturo" -kK
    SSH password: 
    BECOME password[defaults to SSH password]: 
    
    PLAY [all] ************************************************************************
    
    TASK [Gathering Facts] ************************************************************
    ok: [localhost]
    
    TASK [Make sure we have a "wheel" group] ******************************************
    changed: [localhost]
    
    TASK [Allow 'wheel' group to have passwordless sudo] ******************************
    changed: [localhost]
    
    TASK [Create "ansible" user] ******************************************************
    changed: [localhost]
    
    TASK [Add ssh key] ****************************************************************
    changed: [localhost]
    
    PLAY RECAP ************************************************************************
    localhost                  : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

    Awesome, we have sucessfully created a new user!

    Let’s try to connect using the ansible user with its key, as defined in the playbook.

    $ ansible -m ping -i inventory.yml all
    localhost | SUCCESS => {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "ping": "pong"
    }
    

    Stay tuned for more automation using Ansible.