diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..8800e99 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,3 @@ +warn_list: + - '106' + - '204' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0cd61fb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,80 @@ +--- +name: CI +'on': + pull_request: + push: + branches: + - master + schedule: + - cron: '30 1 * * 3' + +jobs: + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + + - name: Set up Python 3 + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install test dependencies + run: pip install ansible-lint[community,yamllint] + + - name: Lint code + run: | + yamllint . + ansible-lint + + molecule: + name: Molecule + runs-on: ubuntu-latest + defaults: + run: + working-directory: "${{ github.repository }}" + needs: + - lint + strategy: + fail-fast: false + matrix: + include: + - distro: debian8 + - distro: debian9 + - distro: debian10 + - distro: ubuntu1604 + ansible-version: '>=2.8, <2.9' + - distro: ubuntu1604 + ansible-version: '>=2.9, <2.10' + - distro: ubuntu1604 + ansible-version: '>=2.10, <2.11' + - distro: ubuntu1604 + - distro: ubuntu1804 + - distro: ubuntu2004 + + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + with: + path: "${{ github.repository }}" + + - name: Set up Python 3 + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install test dependencies + run: pip install 'ansible${{ matrix.ansible-version }}' molecule[docker] docker + + - name: Run Molecule tests + run: | + molecule test + env: + ANSIBLE_FORCE_COLOR: '1' + ANSIBLE_VERBOSITY: '3' + MOLECULE_DEBUG: '1' + MOLECULE_DISTRO: "${{ matrix.distro }}" + PY_COLORS: '1' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2354e68 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,20 @@ +--- +name: Release +'on': + push: + tags: + - '*' + +jobs: + + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + + - name: Publish to Galaxy + uses: robertdebock/galaxy-action@1.1.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1342543..0000000 --- a/.travis.yml +++ /dev/null @@ -1,99 +0,0 @@ ---- -sudo: required -dist: xenial - -language: python -python: - - "2.7" - - "3.5" - -env: - - ANSIBLE_VERSION=latest - - ANSIBLE_VERSION=2.10.2 - - ANSIBLE_VERSION=2.10.1 - - ANSIBLE_VERSION=2.10.0 - - ANSIBLE_VERSION=2.9.14 - - ANSIBLE_VERSION=2.9.13 - - ANSIBLE_VERSION=2.9.12 - - ANSIBLE_VERSION=2.9.11 - - ANSIBLE_VERSION=2.9.10 - - ANSIBLE_VERSION=2.9.9 - - ANSIBLE_VERSION=2.9.8 - - ANSIBLE_VERSION=2.9.7 - - ANSIBLE_VERSION=2.9.6 - - ANSIBLE_VERSION=2.9.5 - - ANSIBLE_VERSION=2.9.4 - - ANSIBLE_VERSION=2.9.3 - - ANSIBLE_VERSION=2.9.2 - - ANSIBLE_VERSION=2.9.1 - - ANSIBLE_VERSION=2.9.0 - - ANSIBLE_VERSION=2.8.16 - - ANSIBLE_VERSION=2.8.15 - - ANSIBLE_VERSION=2.8.14 - - ANSIBLE_VERSION=2.8.13 - - ANSIBLE_VERSION=2.8.12 - - ANSIBLE_VERSION=2.8.11 - - ANSIBLE_VERSION=2.8.10 - - ANSIBLE_VERSION=2.8.9 - - ANSIBLE_VERSION=2.8.8 - - ANSIBLE_VERSION=2.8.7 - - ANSIBLE_VERSION=2.8.6 - - ANSIBLE_VERSION=2.8.5 - - ANSIBLE_VERSION=2.8.4 - - ANSIBLE_VERSION=2.8.3 - - ANSIBLE_VERSION=2.8.2 - - ANSIBLE_VERSION=2.8.1 - - ANSIBLE_VERSION=2.8.0 - -branches: - only: - - master - -before_install: - - sudo apt-get update -qq - -install: - # Install Ansible. - - if [ "$ANSIBLE_VERSION" = "latest" ]; then pip install ansible; else pip install ansible==$ANSIBLE_VERSION; fi - - if [ "$ANSIBLE_VERSION" = "latest" ]; then pip install ansible-lint; fi - -script: - # Check the role/playbook's syntax. - - ansible-playbook -i tests/inventory tests/test.yml --syntax-check - - # Run the role/playbook with ansible-playbook. - - ansible-playbook -i tests/inventory tests/test.yml -vvvv - - # Run the role/playbook again, checking to make sure it's idempotent. - - > - ansible-playbook -i tests/inventory tests/test.yml - | grep -q 'changed=0.*failed=0' - && (echo 'Idempotence test: pass' && exit 0) - || (echo 'Idempotence test: fail' && exit 1) - - # Check presence of private key. - - > - sudo diff files/id_rsa ~root/.ssh/id_rsa - && (echo 'Private key test: pass' && exit 0) - || (echo 'Private key test: fail' && exit 1) - - # Check presence of public key. - - > - sudo diff files/id_rsa.pub ~root/.ssh/id_rsa.pub - && (echo 'Public key test: pass' && exit 0) - || (echo 'Public key test: fail' && exit 1) - - # Check presence of known hosts. - - > - grep -q 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa' /etc/ssh/ssh_known_hosts - && (echo 'Known hosts test: pass' && exit 0) - || (echo 'Known hosts test: fail' && exit 1) - - - if [ "$ANSIBLE_VERSION" = "latest" ]; then ansible-lint tests/test.yml; fi - -notifications: - email: false - webhooks: https://galaxy.ansible.com/api/v1/notifications/ - slack: - rooms: - secure: "e5SGz31omLdaVUKBf6+aH2Lo7vVmi8ZY1MMRkPVAXXLvzpys1pEAbmqKAcx0FQRACEaZbuluhDb8GKkyPfYVbYFxEJK2H1rypQDMdXbI2vOItxRcsPU32PF4SxNZGpuX8ad1Oi3t49FUfIPiJBTxxBCLXUhxdbfKILOE8oZmYyIJyEyevX3Mo0cbTQfPOvoeRbGf1orObmzXQOWc6kgKynGME9E/vYRqT1buPmDQgTnNO0pga+oY99o7W60R9vI31kRuIR152mljnWEG5atrvL6evSn7mRvIU9grr/VFohCC9iBCyCcoXQAt+8BoWKMz5yhjbn0LeW7yDCe6pK4Q6xDVMr8lfdrLfdy24ma20M3KRfYUsCLoKb+VaFB5u1o8Mt3mFkdSWpujknivCx1ft2QkUxnHRFuUVwx0W0evDLqioTehr/Y0lIBt8NSgT0i1wX6nUk+EFijeY1ZBaM3Pflq/8ZFIC0nk5uiqz/WPrLtvVxrQ1y4KllrUFkBqX3pWlKAohjGKZAbPUHaCeB4teVAcJg+Q/uDEqeemuhQpqOlfj7VuSOadd+sUicTYQfAvQWsYsjPki3OW+joFp86rqj2IhdZ/HPR9caMQzV1sASRLZKdgjxeaGmT6LydGZqztB+K+JlJ0cLc1JOleln1GTHclOkyHdhOklIjdQPgHvjg=" diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..894450c --- /dev/null +++ b/.yamllint @@ -0,0 +1,15 @@ +--- +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + line-length: disable + truthy: disable + +ignore: | + .tox/ diff --git a/Dockerfile b/Dockerfile index 6d8d75c..b179278 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,4 +17,4 @@ RUN rm -rf $HOME/.cache # provision COPY . /etc/ansible/roles/ansible-role WORKDIR /etc/ansible/roles/ansible-role -RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local -vv +RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local diff --git a/README.md b/README.md index 87a0396..29d4ab0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## ssh-keys -[![Build Status](https://travis-ci.org/Oefenweb/ansible-ssh-keys.svg?branch=master)](https://travis-ci.org/Oefenweb/ansible-ssh-keys) +[![CI](https://github.com/Oefenweb/ansible-ssh-keys/workflows/CI/badge.svg)](https://github.com/Oefenweb/ansible-ssh-keys/actions?query=workflow%3ACI) [![Ansible Galaxy](http://img.shields.io/badge/ansible--galaxy-ssh--keys-blue.svg)](https://galaxy.ansible.com/Oefenweb/ssh_keys) Manage ssh public key authentication (public / private / authorized keys and known hosts) in Debian-like systems. @@ -83,8 +83,6 @@ None fingerprint: 'AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' ``` -The `fingerprint` and `enctype` can be obtained using `ssh-keyscan`: `ssh-keyscan github.com` or the handy `ssh-keyscan` wrapper included in this role. - #### License MIT diff --git a/Vagrantfile b/Vagrantfile index 3517233..a0182a0 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -4,40 +4,26 @@ role = File.basename(File.expand_path(File.dirname(__FILE__))) boxes = [ - { - :name => "ubuntu-1204", - :box => "bento/ubuntu-12.04", - :ip => '10.0.0.11', - :cpu => "50", - :ram => "256" - }, - { - :name => "ubuntu-1404", - :box => "bento/ubuntu-14.04", - :ip => '10.0.0.12', - :cpu => "50", - :ram => "256" - }, { :name => "ubuntu-1604", :box => "bento/ubuntu-16.04", - :ip => '10.0.0.13', + :ip => '10.0.0.12', :cpu => "50", :ram => "256" }, { :name => "ubuntu-1804", :box => "bento/ubuntu-18.04", - :ip => '10.0.0.14', + :ip => '10.0.0.13', :cpu => "50", :ram => "384" }, { - :name => "debian-7", - :box => "bento/debian-7", - :ip => '10.0.0.15', + :name => "ubuntu-2004", + :box => "bento/ubuntu-20.04", + :ip => '10.0.0.14', :cpu => "50", - :ram => "256" + :ram => "384" }, { :name => "debian-8", diff --git a/meta/main.yml b/meta/main.yml index df897ca..0c8b88c 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -2,7 +2,7 @@ --- galaxy_info: namespace: oefenweb - role_name: ssh-keys + role_name: ssh_keys author: Mischa ter Smitten company: Oefenweb.nl B.V. description: Manage ssh public key authentication (public / private / authorized keys and known hosts) in Debian-like systems @@ -11,17 +11,15 @@ galaxy_info: platforms: - name: Ubuntu versions: - - precise - - trusty - xenial - bionic + - focal - name: Debian versions: - - wheezy - jessie - stretch - buster galaxy_tags: - - system - - networking + - system + - networking dependencies: [] diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..153a4fe --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + become: true + tasks: [] + roles: + - ../../../ diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..fbb7120 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,19 @@ +--- +dependency: + name: galaxy +driver: + name: docker +platforms: + - name: instance + image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu1604}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true +provisioner: + name: ansible + playbooks: + prepare: prepare.yml + converge: converge.yml + verify: verify.yml diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml new file mode 100644 index 0000000..9a6673d --- /dev/null +++ b/molecule/default/prepare.yml @@ -0,0 +1,5 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: [] diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml new file mode 100644 index 0000000..44debad --- /dev/null +++ b/molecule/default/verify.yml @@ -0,0 +1,5 @@ +--- +- name: Verify + hosts: all + become: true + tasks: [] diff --git a/ssh-keyscan b/ssh-keyscan deleted file mode 100755 index adff16c..0000000 --- a/ssh-keyscan +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -# -# set -x; -set -e; -set -o pipefail; -# -thisFile="$(readlink -f ${0})"; -thisFilePath="$(dirname ${thisFile})"; - -hostName="${1}"; -noIp="${2}"; - -if [ -z "${hostName}" ]; then -cat << EOF -Usage: ${0} [options] - -This script is a ssh-keyscan wrapper that outputs yaml to be used in the ansible-ssh-keys role. - -Options: - --no-ip Do not add the hosts ip address to the '- hostname: ' part -EOF -exit 1; -fi - -ipAddress="$(nslookup ${hostName} | awk '/^Address: / { print $2 }' || ping -c 1 ${hostName} | head -n 1 | awk -F'[()]' '{print $2}')"; -ssh-keyscan "${hostName}" 2> /dev/null | while read -r line; do - if [ "${noIp}" = '--no-ip' ]; then - echo " - hostname: '${hostName}'"; - else - echo " - hostname: '${hostName},${ipAddress}'"; - fi - echo " enctype: $(echo ${line} | awk '{ print $2 }')"; - echo " fingerprint: '$(echo ${line} | awk '{ print $3 }')'"; -done diff --git a/tasks/generate.yml b/tasks/generate.yml index df0a709..02cdcc6 100644 --- a/tasks/generate.yml +++ b/tasks/generate.yml @@ -6,6 +6,7 @@ path: "{{ item.path | dirname }}" owner: "{{ item.owner }}" group: "{{ item.group | default(item.owner) }}" + mode: 0700 state: directory with_items: "{{ ssh_keys_generate_keys }}" tags: diff --git a/tests/tasks/post.yml b/tests/tasks/post.yml new file mode 100644 index 0000000..f31d893 --- /dev/null +++ b/tests/tasks/post.yml @@ -0,0 +1,34 @@ +# post test file +--- +- name: test presence of private key + shell: > + diff {{ ssh_keys_private_keys[0]['src'] }} ~dummy/.ssh/{{ ssh_keys_private_keys[0]['src'] | basename }} + && (echo 'Private key test: pass' && exit 0) + || (echo 'Private key test: fail' && exit 1) + args: + warn: false + changed_when: false + tags: + - skip_ansible_lint + +- name: test presence of public key + shell: > + diff {{ ssh_keys_public_keys[0]['src'] }} ~dummy/.ssh/{{ ssh_keys_public_keys[0]['src'] | basename }} + && (echo 'Public key test: pass' && exit 0) + || (echo 'Public key test: fail' && exit 1) + args: + warn: false + changed_when: false + tags: + - skip_ansible_lint + +- name: test presence of known hosts + shell: > + grep -q 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa' /etc/ssh/ssh_known_hosts + && (echo 'Known hosts test: pass' && exit 0) + || (echo 'Known hosts test: fail' && exit 1) + args: + warn: false + changed_when: false + tags: + - skip_ansible_lint diff --git a/tests/pre.yml b/tests/tasks/pre.yml similarity index 50% rename from tests/pre.yml rename to tests/tasks/pre.yml index fd6e01f..a05adef 100644 --- a/tests/pre.yml +++ b/tests/tasks/pre.yml @@ -1,6 +1,6 @@ # pre test file --- -- name: pre | install dependencies +- name: install dependencies apt: name: - openssh-client @@ -8,9 +8,13 @@ update_cache: true cache_valid_time: "{{ apt_update_cache_valid_time | default(3600) }}" -- name: pre | generate key pair +- name: generate key pair command: > - ssh-keygen -t rsa -b 2048 -C '' -P '' -f {{ playbook_dir }}/../files/id_rsa -q + ssh-keygen -t rsa -b 2048 -C '' -P '' -f {{ ssh_keys_private_keys[0]['src'] }} -q args: - creates: "{{ playbook_dir }}/../files/id_rsa" + creates: "{{ ssh_keys_private_keys[0]['src'] }}" become: false + +- name: create user (if needed) + user: + name: dummy diff --git a/tests/test.yml b/tests/test.yml index 05ab4d6..ca5ea5e 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -4,20 +4,12 @@ connection: local become: true pre_tasks: - - import_tasks: pre.yml + - name: include vars + include_vars: "{{ playbook_dir }}/vars/main.yml" + - name: include tasks + include: "{{ playbook_dir }}/tasks/pre.yml" roles: - ../../ - vars: - ssh_keys_private_keys: - - owner: root - src: id_rsa - ssh_keys_public_keys: - - owner: root - src: id_rsa.pub - ssh_keys_authorized_keys: - - owner: root - src: id_rsa.pub - ssh_keys_known_hosts: - - hostname: github.com - enctype: ssh-rsa - fingerprint: 'AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' # noqa 204 + post_tasks: + - name: include tasks + include: "{{ playbook_dir }}/tasks/post.yml" diff --git a/tests/vagrant.yml b/tests/vagrant.yml index afdaebc..3dfeb1c 100644 --- a/tests/vagrant.yml +++ b/tests/vagrant.yml @@ -3,5 +3,13 @@ - hosts: all remote_user: vagrant become: true + pre_tasks: + - name: include vars + include_vars: "{{ playbook_dir }}/vars/main.yml" + - name: include tasks + include: "{{ playbook_dir }}/tasks/pre.yml" roles: - ../../ + post_tasks: + - name: include tasks + include: "{{ playbook_dir }}/tasks/post.yml" diff --git a/tests/vars/main.yml b/tests/vars/main.yml new file mode 100644 index 0000000..f391664 --- /dev/null +++ b/tests/vars/main.yml @@ -0,0 +1,15 @@ +# vars file +--- +ssh_keys_private_keys: + - owner: dummy + src: "{{ playbook_dir }}/../files/id_rsa" +ssh_keys_public_keys: + - owner: dummy + src: "{{ playbook_dir }}/../files/id_rsa.pub" +ssh_keys_authorized_keys: + - owner: dummy + src: "{{ playbook_dir }}/../files/id_rsa.pub" +ssh_keys_known_hosts: + - hostname: github.com + enctype: ssh-rsa + fingerprint: 'AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' # noqa 204