Add SSHD role, tighten things down

This commit is contained in:
Salt 2021-03-11 08:04:57 -06:00
parent 9216ed876d
commit 9070869327
73 changed files with 2784 additions and 0 deletions

View File

@ -5,6 +5,12 @@
# MAD PROPS to geerlingguy; if for some reason you end up reading this, hit me
# up and I'll buy you a beer or a pizza or something.
# SSHD
# Upstream: https://github.com/willshersystems/ansible-sshd
- src: willshersystems.sshd
version: v0.12.0
name: sshd
# DHCP
# Upstream: https://github.com/bertvv/ansible-role-dhcp
- src: bertvv.dhcp

2
roles/sshd/.ansible-lint Normal file
View File

@ -0,0 +1,2 @@
warn_list: # or 'skip_list' to silence them completely │
- '106' # Role name {} does not match ``^[a-z][a-z0-9_]+$`` pattern

View File

@ -0,0 +1,16 @@
name: Run tests on CentOS 7
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ansible check with centos:7
uses: roles-ansible/check-ansible-centos-centos7-action@master
with:
group: local
hosts: localhost
targets: "tests/*.yml"

View File

@ -0,0 +1,16 @@
name: Run tests on CentOS 8
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ansible check with centos:8
uses: roles-ansible/check-ansible-centos-centos8-action@master
with:
group: local
hosts: localhost
targets: "tests/*.yml"

View File

@ -0,0 +1,17 @@
name: Run tests on Fedora latest
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
# Important: This sets up your GITHUB_WORKSPACE environment variable
- uses: actions/checkout@v2
- name: ansible check with fedora:latest
uses: roles-ansible/check-ansible-fedora-latest-action@master
with:
group: local
hosts: localhost
targets: "tests/*.yml"

View File

@ -0,0 +1,38 @@
name: Ansible Lint # feel free to pick your own name
on: [push, pull_request]
jobs:
# test-ansible28:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Lint Ansible Playbook
# uses: ansible/ansible-lint-action@master
# with:
# targets: "tests/test_*.yml"
# override-deps: |
# ansible==2.8
# args: ""
# test-ansible29:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Lint Ansible Playbook
# uses: ansible/ansible-lint-action@master
# with:
# targets: "tests/test_*.yml"
# override-deps: |
# ansible==2.9
# args: ""
test-ansible210:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Lint Ansible Playbook
uses: ansible/ansible-lint-action@master
with:
targets: "tests/test_*.yml"
override-deps: |
ansible==2.10
args: ""

2
roles/sshd/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.vagrant
tests/test.retry

View File

@ -0,0 +1,14 @@
---
repos:
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.24.2
hooks:
- id: yamllint
files: \.(yaml|yml)$
types: [file, yaml]
entry: yamllint --strict
- repo: https://github.com/ansible/ansible-lint.git
rev: v4.3.5
hooks:
- id: ansible-lint
files: \.(yaml|yml)$

80
roles/sshd/.travis.yml Normal file
View File

@ -0,0 +1,80 @@
---
os: linux
dist: focal
language: python
addons:
apt_packages:
- yamllint
notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/
before_install:
- sudo -H pip3 install ansible
install:
# Add ansible.cfg to pick up roles path.
- "{ echo '[defaults]'; echo 'roles_path = ../'; echo 'deprecation_warnings=False'; } >> ansible.cfg"
script:
# Test 0a: Check the roles syntax.
- "ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_default.yml --syntax-check"
# Test 0b: Run yamllint with galaxy configuration to avoid quality score penalty
- wget https://raw.githubusercontent.com/ansible/galaxy/devel/galaxy/importer/linters/yamllint.yaml
- "yamllint -c yamllint.yaml **/*.yml"
# Test 1a: Run the role
- "ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_default.yml --connection=local --become -v"
# Test 1b: Run the role through include
- "ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_default_include.yml --connection=local --become -v"
# Test 2: Run the role/playbook again, checking to make sure it's idempotent.
- >
ansible-playbook -i tests/inventory tests/tests_default.yml --connection=local --become | grep -q 'changed=0.*failed=0'
&& (echo 'Idempotence test: pass' && exit 0)
|| (echo 'Idempotence test: fail' && exit 1)
# Test 3: Check we can set arbitrary configuration options
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_set_common.yml --connection=local --become -v
&& (echo 'Common variables test: pass' && exit 0)
|| (echo 'Common variables test: fail' && exit 1)
# Test 4: Check if we set uncommon or unsupported configuration option, it will not fail hard
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_set_uncommon.yml --connection=local --become -v
&& (echo 'Uncommon configuration test: pass' && exit 0)
|| (echo 'Uncommon configuration test: fail' && exit 1)
# Test 5: Make sure we can modify other files, for example for inclusion
# in the main sshd_config or second sshd service
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_alternative_file.yml --connection=local --become -v
&& (echo 'Alternative configuration file test: pass' && exit 0)
|| (echo 'Alternative configuration file test: fail' && exit 1)
# Test 6: Test match blocks generators
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_match.yml --connection=local --become -v
&& (echo 'Match blocks test: pass' && exit 0)
|| (echo 'Match blocks test: fail' && exit 1)
# Test 7: Test match blocks generators with iteration
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_match_iterate.yml --connection=local --become -v
&& (echo 'Match blocks with iteration test: pass' && exit 0)
|| (echo 'Match blocks with iteration test: fail' && exit 1)
# Test 8: Test hostkeys can be generated by this role
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_hostkeys.yml --connection=local --become -v
&& (echo 'Hostkeys test: pass' && exit 0)
|| (echo 'Hostkeys test: fail' && exit 1)
# Test 9: Test missing hostkeys
- >
ANSIBLE_FORCE_COLOR=1 ansible-playbook -i tests/inventory tests/tests_hostkeys_missing.yml --connection=local --become -v
&& (echo 'Missing hostkeys test: pass' && exit 0)
|| (echo 'Missing hostkeys test: fail' && exit 1)

21
roles/sshd/.yamllint.yaml Normal file
View File

@ -0,0 +1,21 @@
---
# Based on ansible-lint config
extends: default
rules:
braces: {max-spaces-inside: 1, level: error}
brackets: {max-spaces-inside: 1, level: error}
colons: {max-spaces-after: -1, level: error}
commas: {max-spaces-after: -1, level: error}
comments: disable
comments-indentation: disable
document-start: disable
empty-lines: {max: 3, level: error}
hyphens: {level: error}
indentation: disable
key-duplicates: enable
line-length: disable
new-line-at-end-of-file: disable
new-lines: {type: unix}
trailing-spaces: disable
truthy: disable

27
roles/sshd/CHANGELOG Normal file
View File

@ -0,0 +1,27 @@
0.2.5 23 January 2014 Matt Willsher <matt@willsher.systems>
- Fix for sftp-server install on Debian removing openssh-sftp-server. Thanks to @ricbra
- Reinstate defaults.yml as fall through
0.2.4 13 January 2014 Matt Willsher <matt@willsher.systems>
- Allow reload to be skipped
- Test for OS support
- Documentation improvements
0.2.3 13 January 2014 Matt Willsher <matt@willsher.systems>
- Fixed HostbasedAuthentication typo
0.2.2 13 January 2014 Matt Willsher <matt@willsher.systems>
- Add warnings to README
- Tidy up naming
- Remove blacklist packages from Debian based distros
0.2.1 12 January 2014 Matt Willsher <matt@willsher.systems>
- Standardise README.md format
- Add basic Travis CI testing
- Add networking metadata type
0.2.0 04 January 2014 Matt Willsher <matt@willsher.systems>
- Change var file search order
- Add Arch Linux defaults (thanks GitHub user @brenix).
- A number of typo fixes (again, thanks @brenix), including UsePrivilegeSeparation.
- A Ubuntu precise defaults.
- A Debian jessie defaults.
- Unknown Ubuntu and Debian versions default to wheezy defaults.
- License to LGPL
0.1.0 25 December 2014 Matt Willsher <matt@willsher.systems>
- Initial release

View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at matt@willsher.systems. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

165
roles/sshd/LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

299
roles/sshd/README.md Normal file
View File

@ -0,0 +1,299 @@
OpenSSH Server
==============
[![Build Status](https://travis-ci.org/willshersystems/ansible-sshd.svg?branch=master)](https://travis-ci.org/willshersystems/ansible-sshd) [![Ansible Galaxy](http://img.shields.io/badge/galaxy-willshersystems.sshd-660198.svg?style=flat)](https://galaxy.ansible.com/willshersystems/sshd/)
This role configures the OpenSSH daemon. It:
* By default configures the SSH daemon with the normal OS defaults.
* Works across a variety of `UN*X` distributions
* Can be configured by dict or simple variables
* Supports Match sets
* Supports all `sshd_config` options. Templates are programmatically generated.
(see [`meta/make_option_list`](meta/make_option_list))
* Tests the `sshd_config` before reloading sshd.
**WARNING** Misconfiguration of this role can lock you out of your server!
Please test your configuration and its interaction with your users configuration
before using in production!
**WARNING** Digital Ocean allows root with passwords via SSH on Debian and
Ubuntu. This is not the default assigned by this module - it will set
`PermitRootLogin without-password` which will allow access via SSH key but not
via simple password. If you need this functionality, be sure to set
`sshd_PermitRootLogin yes` for those hosts.
Requirements
------------
Tested on:
* Ubuntu precise, trusty, xenial, bionic, focal
* Debian wheezy, jessie, stretch, buster
* FreeBSD 10.1
* EL 6, 7, 8 derived distributions
* Fedora 31, 32, 33
* OpenBSD 6.0
* AIX 7.1, 7.2
It will likely work on other flavours and more direct support via suitable
[vars/](vars/) files is welcome.
Role variables
---------------
Unconfigured, this role will provide a `sshd_config` that matches the OS default,
minus the comments and in a different order.
* `sshd_enable`
If set to *false*, the role will be completely disabled. Defaults to *true*.
* `sshd_skip_defaults`
If set to *true*, don't apply default values. This means that you must have a
complete set of configuration defaults via either the `sshd` dict, or
`sshd_Key` variables. Defaults to *false*.
* `sshd_manage_service`
If set to *false*, the service/daemon won't be **managed** at all, i.e. will not
try to enable on boot or start or reload the service. Defaults to *true*
unless: Running inside a docker container (it is assumed ansible is used during
build phase) or AIX (Ansible `service` module does not currently support `enabled`
for AIX)
* `sshd_allow_reload`
If set to *false*, a reload of sshd wont happen on change. This can help with
troubleshooting. You'll need to manually reload sshd if you want to apply the
changed configuration. Defaults to the same value as `sshd_manage_service`.
(Except on AIX, where `sshd_manage_service` is default *false*, but
`sshd_allow_reload` is default *true*)
* `sshd_install_service`
If set to *true*, the role will install service files for the ssh service.
Defaults to *false*.
The templates for the service files to be used are pointed to by the variables
- `sshd_service_template_service` (__default__: `templates/sshd.service.j2`)
- `sshd_service_template_at_service` (__default__: `templates/sshd@.service.j2`)
- `sshd_service_template_socket` (__default__: `templates/sshd.socket.j2`)
Using these variables, you can use your own custom templates. With the above
default templates, the name of the installed ssh service will be provided by
the `sshd_service` variable.
* `sshd`
A dict containing configuration. e.g.
```yaml
sshd:
Compression: delayed
ListenAddress:
- 0.0.0.0
```
* `sshd_...`
Simple variables can be used rather than a dict. Simple values override dict
values. e.g.:
```yaml
sshd_Compression: off
```
In all cases, booleans are correctly rendered as yes and no in sshd
configuration. Lists can be used for multiline configuration items. e.g.
```yaml
sshd_ListenAddress:
- 0.0.0.0
- '::'
```
Renders as:
```
ListenAddress 0.0.0.0
ListenAddress ::
```
* `sshd_match`
A list of dicts for a match section. See the example playbook.
* `sshd_match_1` through `sshd_match_9`
A list of dicts or just a dict for a Match section.
* `sshd_backup`
When set to *false*, the original `sshd_config` file is not backed up. Default
is *true*.
* `sshd_sysconfig`
On RHEL-based systems, sysconfig is used for configuring more details of sshd
service. If set to *true*, this role will manage also the `/etc/sysconfig/sshd`
configuration file based on the following configuration. Default is *false*.
* `sshd_sysconfig_override_crypto_policy`
In RHEL8-based systems, this can be used to override system-wide crypto policy
by setting to *true*. Defaults to *false*.
* `sshd_sysconfig_use_strong_rng`
In RHEL-based systems, this can be used to force sshd to reseed openssl random
number generator with the given amount of bytes as an argument. The default is
*0*, which disables this functionality. It is not recommended to turn this on
if the system does not have hardware random number generator.
* `sshd_config_file`
The path where the openssh configuration produced by this role should be saved.
This is useful mostly when generating configuration snippets to Include.
### Secondary role variables
These variables are used by the role internals and can be used to override the
defaults that correspond to each supported platform.
* `sshd_packages`
Use this variable to override the default list of packages to install.
* `sshd_config_owner`, `sshd_config_group`, `sshd_config_mode`
Use these variables to set the ownership and permissions for the openssh config
file that this role produces.
* `sshd_binary`
The path to the openssh executable
* `sshd_service`
The name of the openssh service. By default, this variable contains the name of
the ssh service that the target platform uses. But it can also be used to set
the name of the custom ssh service when the `sshd_install_service` variable is
used.
* `sshd_verify_hostkeys`
By default (*auto*), this list contains all the host keys that are present in
the produced configuration file. The paths are checked for presence and
generated if missing. Additionally, permissions and file owners are set to sane
defaults. This is useful if the role is used in deployment stage to make sure
the service is able to start on the first attempt. To disable this check, set
this to empty list.
* `sshd_hostkey_owner`, `sshd_hostkey_group`, `sshd_hostkey_group`
Use these variables to set the ownership and permissions for the host keys from
the above list.
* `sshd_sftp_server`
Default path to the sftp server binary.
Dependencies
------------
None
Example Playbook
----------------
**DANGER!** This example is to show the range of configuration this role
provides. Running it will likely break your SSH access to the server!
```yaml
---
- hosts: all
vars:
sshd_skip_defaults: true
sshd:
Compression: true
ListenAddress:
- "0.0.0.0"
- "::"
GSSAPIAuthentication: no
Match:
- Condition: "Group user"
GSSAPIAuthentication: yes
sshd_UsePrivilegeSeparation: no
sshd_match:
- Condition: "Group xusers"
X11Forwarding: yes
roles:
- role: willshersystems.sshd
```
Results in:
```
# Ansible managed: ...
Compression yes
GSSAPIAuthentication no
UsePrivilegeSeparation no
Match Group user
GSSAPIAuthentication yes
Match Group xusers
X11Forwarding yes
```
Since Ansible 2.4, the role can be invoked using `include_role` keyword,
for example:
```yaml
---
- hosts: all
become: true
tasks:
- name: "Configure sshd"
include_role:
name: willshersystems.sshd
vars:
sshd_skip_defaults: true
sshd:
Compression: true
ListenAddress:
- "0.0.0.0"
- "::"
GSSAPIAuthentication: no
Match:
- Condition: "Group user"
GSSAPIAuthentication: yes
sshd_UsePrivilegeSeparation: no
sshd_match:
- Condition: "Group xusers"
X11Forwarding: yes
```
Template Generation
-------------------
The [`sshd_config.j2`](templates/sshd_config.j2) template is programatically
generated by the scripts in meta. New options should be added to the
`options_body` or `options_match`.
To regenerate the template, from within the meta/ directory run:
`./make_option_list >../templates/sshd_config.j2`
License
-------
LGPLv3
Author
------
Matt Willsher <matt@willsher.systems>
&copy; 2014,2015 Willsher Systems Ltd.

37
roles/sshd/Vagrantfile vendored Normal file
View File

@ -0,0 +1,37 @@
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder ".", "/vagrant", type: "nfs"
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.box = "boxcutter/ubuntu1604"
# ubuntu.vm.provision "shell", inline: <<-SHELL
# sudo add-apt-repository -y ppa:ansible/ansible
# sudo apt-get update -qq
# sudo apt-get -qq install ansible
# SHELL
end
config.vm.define "centos7" do |centos|
centos.vm.box = "centos/7"
centos.vm.provision "shell", inline: <<-SHELL
sudo yum install -y libselinux-python
SHELL
end
config.vm.provision "shell", inline: <<-SHELL
test -e /vagrant/tests/roles/ansible-sshd || ln -s /vagrant /vagrant/tests/roles/ansible-sshd
SHELL
config.vm.provision "ansible_local" do |ansible|
# ansible.config_file = "tests/ansible.cfg"
ansible.playbook = "tests/test.yml"
ansible.install = true
end
end

View File

@ -0,0 +1,72 @@
---
### USER OPTIONS
# Set to false to disable this role completely
sshd_enable: true
# Don't apply OS defaults when set to true
sshd_skip_defaults: false
# If the below is false, don't manage the service or reload the SSH
# daemon at all
sshd_manage_service: true
# If the below is false, don't reload the ssh daemon on change
sshd_allow_reload: true
# If the below is true, also install service files from the templates pointed
# to by the `sshd_service_template_*` variables
sshd_install_service: false
sshd_service_template_service: sshd.service.j2
sshd_service_template_at_service: sshd@.service.j2
sshd_service_template_socket: sshd.socket.j2
# If the below is true, create a backup of the config file when the template is copied
sshd_backup: true
# If the below is true, also install the sysconfig file with the below options
# (useful only on Fedora and RHEL)
sshd_sysconfig: false
# If the below is true the role will override also crypto policy configuration
sshd_sysconfig_override_crypto_policy: false
# If the below is set to non-zero value, the OpenSSL random generator is
# reseeded with the given amount of random bytes (from getrandom(2)
# with GRND_RANDOM or /dev/random). Minimum is 14 bytes when enabled.
# This is not recommended to enable if you do not have hardware random number
# generator
sshd_sysconfig_use_strong_rng: 0
# Empty dicts to avoid errors
sshd: {}
# The path to sshd_config file. This is useful when creating an included
# configuration file snippet or configuring second sshd service
sshd_config_file: /etc/ssh/sshd_config
### VARS DEFAULTS
### The following are defaults for OS specific configuration in var files in
### this role. They should not be set directly by role users.
sshd_packages: []
sshd_config_owner: root
sshd_config_group: root
sshd_config_mode: "0600"
sshd_binary: /usr/sbin/sshd
sshd_service: sshd
sshd_sftp_server: /usr/lib/openssh/sftp-server
# This lists by default all hostkeys as rendered in the generated configuration
# file ("auto"). Before attempting to run sshd (either for verification of
# configuration or restarting), we make sure the keys exist and have correct
# permissions. To disable this check, set sshd_verify_hostkeys to false
sshd_verify_hostkeys: "auto"
sshd_hostkey_owner: root
sshd_hostkey_group: root
sshd_hostkey_mode: "0600"
### These variables are used by role internals and should not be used.
__sshd_defaults: {}
__sshd_os_supported: no
__sshd_sysconfig_supports_crypto_policy: false
__sshd_sysconfig_supports_use_strong_rng: false

View File

@ -0,0 +1,27 @@
---
- name: Reload the SSH service
service:
name: "{{ sshd_service }}"
state: reloaded
when:
- sshd_allow_reload|bool
- ansible_virtualization_type|default(None) != 'docker'
- ansible_virtualization_type|default(None) != 'VirtualPC' # for Github Actions
- ansible_connection != 'chroot'
- ansible_os_family != 'AIX'
listen: reload_sshd
# sshd on AIX cannot be 'reloaded', it must be Stopped+Started.
# It's dangerous to do this in two tasks.. you're stopping SSH and then trying to SSH back in to start it.
# Instead, use a dirty shell script:
# https://www.ibm.com/developerworks/community/blogs/brian/entry/scripting_the_stop_and_restart_of_src_controlled_processes_on_aix6
- name: Reload sshd Service (AIX)
shell: |
stopsrc -s sshd
until $(lssrc -s sshd | grep -q inoperative); do sleep 1; done
startsrc -s sshd
listen: reload_sshd
when:
- sshd_allow_reload|bool
- ansible_os_family == 'AIX'

View File

@ -0,0 +1,2 @@
install_date: Thu Mar 11 13:56:57 2021
version: v0.12.0

35
roles/sshd/meta/10_top.j2 Normal file
View File

@ -0,0 +1,35 @@
# {{ ansible_managed }}
{% macro render_option(key,value,indent=false) %}
{% if value is defined %}
{% if indent == true %} {% endif %}
{% if value is sameas true %}
{{ key }} yes
{% elif value is sameas false %}
{{ key }} no
{% elif value is string or value is number %}
{{ key }} {{ value }}
{% else %}
{% for i in value %}
{{ key }} {{ i }}
{% endfor %}
{% endif %}
{% endif %}
{% endmacro %}
{% macro body_option(key,override) %}
{% set value = undefined %}
{% if override is defined %}
{% set value = override %}
{% elif sshd[key] is defined %}
{% set value = sshd[key] %}
{% elif __sshd_defaults[key] is defined and sshd_skip_defaults != true %}
{% set value = __sshd_defaults[key] %}
{% endif %}
{{ render_option(key,value) -}}
{% endmacro %}
{% macro match_block(match_list) %}
{% if match_list["Condition"] is defined %}
{% set match_list = [ match_list ]%}
{% endif %}
{% if match_list is iterable %}
{% for match in match_list %}
Match {{ match["Condition"] }}

View File

@ -0,0 +1,3 @@
{% endfor %}
{% endif %}
{% endmacro %}

View File

@ -0,0 +1,33 @@
{% if sshd['Match'] is defined %}
{{ match_block(sshd['Match']) -}}
{% endif %}
{% if sshd_match is defined %}
{{ match_block(sshd_match) -}}
{% endif %}
{% if sshd_match_1 is defined %}
{{ match_block(sshd_match_1) -}}
{% endif %}
{% if sshd_match_2 is defined %}
{{ match_block(sshd_match_2) -}}
{% endif %}
{% if sshd_match_3 is defined %}
{{ match_block(sshd_match_3) -}}
{% endif %}
{% if sshd_match_4 is defined %}
{{ match_block(sshd_match_4) -}}
{% endif %}
{% if sshd_match_5 is defined %}
{{ match_block(sshd_match_5) -}}
{% endif %}
{% if sshd_match_6 is defined %}
{{ match_block(sshd_match_6) -}}
{% endif %}
{% if sshd_match_7 is defined %}
{{ match_block(sshd_match_7) -}}
{% endif %}
{% if sshd_match_8 is defined %}
{{ match_block(sshd_match_8) -}}
{% endif %}
{% if sshd_match_9 is defined %}
{{ match_block(sshd_match_9) -}}
{% endif %}

56
roles/sshd/meta/main.yml Normal file
View File

@ -0,0 +1,56 @@
---
galaxy_info:
author: Matt Willsher
description: OpenSSH SSH daemon configuration
company: Willsher Systems
license: LGPLv3
min_ansible_version: 2.8
platforms:
- name: Debian
versions:
- wheezy
- jessie
- stretch
- buster
- name: Ubuntu
versions:
- precise
- trusty
- xenial
- bionic
- focal
- name: FreeBSD
version:
- 10.1
- name: EL
versions:
- 6
- 7
- 8
- name: Fedora
versions:
- 31
- 32
- 33
- name: OpenBSD
versions:
- 6.0
- name: AIX
versions:
- 7.1
- 7.2
galaxy_tags:
- networking
- system
- ssh
- openssh
- sshd
- server
- ubuntu
- debian
- centos
- redhat
- freebsd
- openbsd
- aix
dependencies: []

View File

@ -0,0 +1,16 @@
#!/bin/sh
cat 10_top.j2
cat options_match |
awk '{
print "{{ render_option(\""$1"\",match[\""$1"\"],true) -}}"
}'
cat 20_middle.j2
cat options_body |
awk '{
print "{{ body_option(\""$1"\",sshd_"$1") -}}"
}'
cat 30_bottom.j2

View File

@ -0,0 +1,107 @@
Port
AddressFamily
ListenAddress
Protocol
HostKey
AcceptEnv
AllowAgentForwarding
AllowGroups
AllowStreamLocalForwarding
AllowTcpForwarding
AllowUsers
AuthenticationMethods
AuthorizedKeysCommand
AuthorizedKeysCommandUser
AuthorizedKeysFile
AuthorizedPrincipalsCommand
AuthorizedPrincipalsCommandUser
AuthorizedPrincipalsFile
Banner
CASignatureAlgorithms
ChallengeResponseAuthentication
ChrootDirectory
Ciphers
ClientAliveCountMax
ClientAliveInterval
Compression
DebianBanner
DenyGroups
DenyUsers
DisableForwarding
ExposeAuthInfo
FingerprintHash
ForceCommand
GatewayPorts
GSSAPIAuthentication
GSSAPICleanupCredentials
GSSAPIKeyExchange
GSSAPIKexAlgorithms
GSSAPIStoreCredentialsOnRekey
GSSAPIStrictAcceptorCheck
HPNBufferSize
HPNDisabled
HostCertificate
HostKeyAgent
HostKeyAlgorithms
HostbasedAcceptedKeyTypes
HostbasedAuthentication
HostbasedUsesNameFromPacketOnly
Include
IPQoS
IgnoreRhosts
IgnoreUserKnownHosts
KbdInteractiveAuthentication
KerberosAuthentication
KerberosGetAFSToken
KerberosOrLocalPasswd
KerberosTicketCleanup
KexAlgorithms
KeyRegenerationInterval
LogLevel
LoginGraceTime
MACs
MaxAuthTries
MaxSessions
MaxStartups
NoneEnabled
PasswordAuthentication
PermitEmptyPasswords
PermitListen
PermitOpen
PermitRootLogin
PermitTTY
PermitTunnel
PermitUserEnvironment
PermitUserRC
PidFile
PrintLastLog
PrintMotd
PubkeyAcceptedKeyTypes
PubkeyAuthOptions
PubkeyAuthentication
RSAAuthentication
RekeyLimit
RevokedKeys
RDomain
RhostsRSAAuthentication
SecurityKeyProvider
SetEnv
ServerKeyBits
StreamLocalBindMask
StreamLocalBindUnlink
StrictModes
Subsystem
SyslogFacility
TCPKeepAlive
TcpRcvBufPoll
TrustedUserCAKeys
UseDNS
UseLogin
UsePAM
UsePrivilegeSeparation
VersionAddendum
X11DisplayOffset
X11MaxDisplays
X11Forwarding
X11UseLocalhost
XAuthLocation

View File

@ -0,0 +1,55 @@
AcceptEnv
AllowAgentForwarding
AllowGroups
AllowStreamLocalForwarding
AllowTcpForwarding
AllowUsers
AuthenticationMethods
AuthorizedKeysCommand
AuthorizedKeysCommandUser
AuthorizedKeysFile
AuthorizedPrincipalsCommand
AuthorizedPrincipalsCommandUser
AuthorizedPrincipalsFile
Banner
ChrootDirectory
ClientAliveCountMax
ClientAliveInterval
DenyGroups
DenyUsers
ForceCommand
GatewayPorts
GSSAPIAuthentication
HostbasedAcceptedKeyTypes
HostbasedAuthentication
HostbasedUsesNameFromPacketOnly
Include
IPQoS
KbdInteractiveAuthentication
KerberosAuthentication
LogLevel
MaxAuthTries
MaxSessions
PasswordAuthentication
PermitEmptyPasswords
PermitListen
PermitOpen
PermitRootLogin
PermitTTY
PermitTunnel
PermitUserRC
PubkeyAcceptedKeyTypes
PubkeyAuthentication
RDomain
RekeyLimit
RevokedKeys
RhostsRSAAuthentication
RSAAuthentication
SetEnv
StreamLocalBindMask
StreamLocalBindUnlink
TrustedUserCAKeys
X11DisplayOffset
X11MaxDisplays
X11Forwarding
X11UseLocalHost

View File

@ -0,0 +1,160 @@
---
- name: OS is supported
meta: end_host
when:
- not __sshd_os_supported|bool
- name: Install ssh packages
package:
name: "{{ sshd_packages }}"
state: present
- name: Sysconfig configuration
template:
src: sysconfig.j2
dest: "/etc/sysconfig/sshd"
owner: "root"
group: "root"
mode: "600"
backup: "{{ sshd_backup }}"
when:
- sshd_sysconfig|bool
notify: reload_sshd
- name: Make sure hostkeys are available and have expected permissions
vars: &share_vars
# This mimics the macro body_option() in sshd_config.j2
# The explicit to_json filter is needed for Python 2 compatibility
__sshd_hostkeys_from_config: >-
{% if sshd_HostKey is defined %}
{{ sshd_HostKey | to_json }}
{% elif sshd['HostKey'] is defined %}
{{ sshd['HostKey'] | to_json }}
{% elif __sshd_defaults['HostKey'] is defined and not sshd_skip_defaults %}
{{ __sshd_defaults['HostKey'] | to_json }}
{% else %}
[]
{% endif %}
__sshd_verify_hostkeys: >-
{% if not sshd_verify_hostkeys %}
[]
{% elif sshd_verify_hostkeys == 'auto' %}
{{ __sshd_hostkeys_from_config }}
{% else %}
{{ sshd_verify_hostkeys | to_json }}
{% endif %}
block:
- name: Make sure hostkeys are available
shell: >
{% if sshd_sysconfig %}
source /etc/sysconfig/sshd;
{% endif %}
ssh-keygen -q -t {{ item | regex_search('(rsa|dsa|ecdsa|ed25519)') }} -f {{ item }} -C '' -N ''
args:
creates: "{{ item }}"
loop: "{{ __sshd_verify_hostkeys | from_json | list }}"
- name: Make sure private hostkeys have expected permissions
file:
path: "{{ item }}"
owner: "{{ sshd_hostkey_owner }}"
group: "{{ sshd_hostkey_group }}"
mode: "{{ sshd_hostkey_mode }}"
loop: "{{ __sshd_verify_hostkeys | from_json | list }}"
- name: Apply configuration
vars:
<<: *share_vars
block:
- name: Create a temporary hostkey for syntax verification if needed
tempfile:
state: directory
register: sshd_test_hostkey
changed_when: False
when:
- __sshd_hostkeys_from_config | from_json == []
- sshd_config_file != "/etc/ssh/sshd_config"
- name: Generate temporary hostkey
shell: "ssh-keygen -q -t rsa -f {{ sshd_test_hostkey.path }}/rsa_key -C '' -N ''"
changed_when: False
when: sshd_test_hostkey.path is defined
- name: Create the configuration file
template:
src: sshd_config.j2
dest: "{{ sshd_config_file }}"
owner: "{{ sshd_config_owner }}"
group: "{{ sshd_config_group }}"
mode: "{{ sshd_config_mode }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s
{% endif %}
backup: "{{ sshd_backup }}"
notify: reload_sshd
rescue:
- name: re-raise the error
fail:
msg: "{{ ansible_failed_result }}"
always:
- name: Remove temporary host keys
file:
path: "{{ sshd_test_hostkey.path }}"
state: absent
changed_when: False
when: sshd_test_hostkey.path is defined
- name: Install systemd service files
block:
- name: Install service unit file
template:
src: "{{ sshd_service_template_service }}"
dest: "/etc/systemd/system/{{ sshd_service }}.service"
owner: root
group: root
mode: "0644"
notify: reload_sshd
- name: Install instanced service unit file
template:
src: "{{ sshd_service_template_at_service }}"
dest: "/etc/systemd/system/{{ sshd_service }}@.service"
owner: root
group: root
mode: "0644"
notify: reload_sshd
- name: Install socket unit file
template:
src: "{{ sshd_service_template_socket }}"
dest: "/etc/systemd/system/{{ sshd_service }}.socket"
owner: root
group: root
mode: "0644"
notify: reload_sshd
when: sshd_install_service|bool
- name: Service enabled and running
service:
name: "{{ sshd_service }}"
enabled: true
state: started
when:
- sshd_manage_service|bool
- ansible_virtualization_type|default(None) != 'docker'
- ansible_virtualization_type|default(None) != 'VirtualPC' # for Github Actions
- ansible_connection != 'chroot'
# Due to ansible bug 21026, cannot use service module on RHEL 7
- name: Enable service in chroot
command: systemctl enable {{ sshd_service }} # noqa 303
when:
- ansible_connection == 'chroot'
- ansible_os_family == 'RedHat'
- ansible_distribution_major_version|int >= 7
- name: Register that this role has run
set_fact:
sshd_has_run: true
when: sshd_has_run is not defined

View File

@ -0,0 +1,4 @@
---
- include_tasks: sshd.yml
when: sshd_enable|bool

View File

@ -0,0 +1,5 @@
---
- include_tasks: variables.yml
- include_tasks: install.yml

View File

@ -0,0 +1,27 @@
---
- name: Set OS dependent variables
include_vars: "{{ lookup('first_found', params) }}"
vars:
ansible_distribution_lts_offset: >-
{{
ansible_distribution_major_version|int % 2
if ansible_distribution == "Ubuntu"
else 0
}}
ansible_distribution_lts_version: >-
{{
ansible_distribution_major_version|int -
ansible_distribution_lts_offset|int
if ansible_distribution == "Ubuntu"
else ansible_distribution_version
}}
params:
files:
- "{{ ansible_distribution }}_{{ ansible_distribution_lts_version }}.yml"
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}_{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_os_family }}.yml"
- default.yml
paths:
- "{{ role_path }}/vars"
- "{{ playbook_dir }}/vars"

View File

@ -0,0 +1,17 @@
[Unit]
Description=OpenBSD Secure Shell server
[Service]
ExecStartPre={{ sshd_binary }} -t
ExecStart={{ sshd_binary }} -D -f {{ sshd_config_file }}
ExecReload={{ sshd_binary }} -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory={{ sshd_binary | basename }}
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=OpenBSD Secure Shell server socket
Before={{ sshd_service }}.service
Conflicts={{sshd_service }}.service
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=OpenBSD Secure Shell server per-connection daemon
After=auditd.service
[Service]
ExecStart=-{{ sshd_binary }} -i -f {{ sshd_config_file }}
StandardInput=socket
RuntimeDirectory={{ sshd_binary }}
RuntimeDirectoryMode=0755

View File

@ -0,0 +1,242 @@
# {{ ansible_managed }}
{% macro render_option(key,value,indent=false) %}
{% if value is defined %}
{% if indent == true %} {% endif %}
{% if value is sameas true %}
{{ key }} yes
{% elif value is sameas false %}
{{ key }} no
{% elif value is string or value is number %}
{{ key }} {{ value }}
{% else %}
{% for i in value %}
{{ key }} {{ i }}
{% endfor %}
{% endif %}
{% endif %}
{% endmacro %}
{% macro body_option(key,override) %}
{% set value = undefined %}
{% if override is defined %}
{% set value = override %}
{% elif sshd[key] is defined %}
{% set value = sshd[key] %}
{% elif __sshd_defaults[key] is defined and sshd_skip_defaults != true %}
{% set value = __sshd_defaults[key] %}
{% endif %}
{{ render_option(key,value) -}}
{% endmacro %}
{% macro match_block(match_list) %}
{% if match_list["Condition"] is defined %}
{% set match_list = [ match_list ]%}
{% endif %}
{% if match_list is iterable %}
{% for match in match_list %}
Match {{ match["Condition"] }}
{{ render_option("AcceptEnv",match["AcceptEnv"],true) -}}
{{ render_option("AllowAgentForwarding",match["AllowAgentForwarding"],true) -}}
{{ render_option("AllowGroups",match["AllowGroups"],true) -}}
{{ render_option("AllowStreamLocalForwarding",match["AllowStreamLocalForwarding"],true) -}}
{{ render_option("AllowTcpForwarding",match["AllowTcpForwarding"],true) -}}
{{ render_option("AllowUsers",match["AllowUsers"],true) -}}
{{ render_option("AuthenticationMethods",match["AuthenticationMethods"],true) -}}
{{ render_option("AuthorizedKeysCommand",match["AuthorizedKeysCommand"],true) -}}
{{ render_option("AuthorizedKeysCommandUser",match["AuthorizedKeysCommandUser"],true) -}}
{{ render_option("AuthorizedKeysFile",match["AuthorizedKeysFile"],true) -}}
{{ render_option("AuthorizedPrincipalsCommand",match["AuthorizedPrincipalsCommand"],true) -}}
{{ render_option("AuthorizedPrincipalsCommandUser",match["AuthorizedPrincipalsCommandUser"],true) -}}
{{ render_option("AuthorizedPrincipalsFile",match["AuthorizedPrincipalsFile"],true) -}}
{{ render_option("Banner",match["Banner"],true) -}}
{{ render_option("ChrootDirectory",match["ChrootDirectory"],true) -}}
{{ render_option("ClientAliveCountMax",match["ClientAliveCountMax"],true) -}}
{{ render_option("ClientAliveInterval",match["ClientAliveInterval"],true) -}}
{{ render_option("DenyGroups",match["DenyGroups"],true) -}}
{{ render_option("DenyUsers",match["DenyUsers"],true) -}}
{{ render_option("ForceCommand",match["ForceCommand"],true) -}}
{{ render_option("GatewayPorts",match["GatewayPorts"],true) -}}
{{ render_option("GSSAPIAuthentication",match["GSSAPIAuthentication"],true) -}}
{{ render_option("HostbasedAcceptedKeyTypes",match["HostbasedAcceptedKeyTypes"],true) -}}
{{ render_option("HostbasedAuthentication",match["HostbasedAuthentication"],true) -}}
{{ render_option("HostbasedUsesNameFromPacketOnly",match["HostbasedUsesNameFromPacketOnly"],true) -}}
{{ render_option("Include",match["Include"],true) -}}
{{ render_option("IPQoS",match["IPQoS"],true) -}}
{{ render_option("KbdInteractiveAuthentication",match["KbdInteractiveAuthentication"],true) -}}
{{ render_option("KerberosAuthentication",match["KerberosAuthentication"],true) -}}
{{ render_option("LogLevel",match["LogLevel"],true) -}}
{{ render_option("MaxAuthTries",match["MaxAuthTries"],true) -}}
{{ render_option("MaxSessions",match["MaxSessions"],true) -}}
{{ render_option("PasswordAuthentication",match["PasswordAuthentication"],true) -}}
{{ render_option("PermitEmptyPasswords",match["PermitEmptyPasswords"],true) -}}
{{ render_option("PermitListen",match["PermitListen"],true) -}}
{{ render_option("PermitOpen",match["PermitOpen"],true) -}}
{{ render_option("PermitRootLogin",match["PermitRootLogin"],true) -}}
{{ render_option("PermitTTY",match["PermitTTY"],true) -}}
{{ render_option("PermitTunnel",match["PermitTunnel"],true) -}}
{{ render_option("PermitUserRC",match["PermitUserRC"],true) -}}
{{ render_option("PubkeyAcceptedKeyTypes",match["PubkeyAcceptedKeyTypes"],true) -}}
{{ render_option("PubkeyAuthentication",match["PubkeyAuthentication"],true) -}}
{{ render_option("RDomain",match["RDomain"],true) -}}
{{ render_option("RekeyLimit",match["RekeyLimit"],true) -}}
{{ render_option("RevokedKeys",match["RevokedKeys"],true) -}}
{{ render_option("RhostsRSAAuthentication",match["RhostsRSAAuthentication"],true) -}}
{{ render_option("RSAAuthentication",match["RSAAuthentication"],true) -}}
{{ render_option("SetEnv",match["SetEnv"],true) -}}
{{ render_option("StreamLocalBindMask",match["StreamLocalBindMask"],true) -}}
{{ render_option("StreamLocalBindUnlink",match["StreamLocalBindUnlink"],true) -}}
{{ render_option("TrustedUserCAKeys",match["TrustedUserCAKeys"],true) -}}
{{ render_option("X11DisplayOffset",match["X11DisplayOffset"],true) -}}
{{ render_option("X11MaxDisplays",match["X11MaxDisplays"],true) -}}
{{ render_option("X11Forwarding",match["X11Forwarding"],true) -}}
{{ render_option("X11UseLocalHost",match["X11UseLocalHost"],true) -}}
{% endfor %}
{% endif %}
{% endmacro %}
{% macro match_iterate_block(match_list) %}
{% if match_list | type_debug == "list" %}
{% for match in match_list %}
{{ match_block(match) -}}
{% endfor %}
{% else %}
{{ match_block(match_list) -}}
{% endif %}
{% endmacro %}
{{ body_option("Port",sshd_Port) -}}
{{ body_option("AddressFamily",sshd_AddressFamily) -}}
{{ body_option("ListenAddress",sshd_ListenAddress) -}}
{{ body_option("Protocol",sshd_Protocol) -}}
{{ body_option("HostKey",sshd_HostKey) -}}
{{ body_option("AcceptEnv",sshd_AcceptEnv) -}}
{{ body_option("AllowAgentForwarding",sshd_AllowAgentForwarding) -}}
{{ body_option("AllowGroups",sshd_AllowGroups) -}}
{{ body_option("AllowStreamLocalForwarding",sshd_AllowStreamLocalForwarding) -}}
{{ body_option("AllowTcpForwarding",sshd_AllowTcpForwarding) -}}
{{ body_option("AllowUsers",sshd_AllowUsers) -}}
{{ body_option("AuthenticationMethods",sshd_AuthenticationMethods) -}}
{{ body_option("AuthorizedKeysCommand",sshd_AuthorizedKeysCommand) -}}
{{ body_option("AuthorizedKeysCommandUser",sshd_AuthorizedKeysCommandUser) -}}
{{ body_option("AuthorizedKeysFile",sshd_AuthorizedKeysFile) -}}
{{ body_option("AuthorizedPrincipalsCommand",sshd_AuthorizedPrincipalsCommand) -}}
{{ body_option("AuthorizedPrincipalsCommandUser",sshd_AuthorizedPrincipalsCommandUser) -}}
{{ body_option("AuthorizedPrincipalsFile",sshd_AuthorizedPrincipalsFile) -}}
{{ body_option("Banner",sshd_Banner) -}}
{{ body_option("CASignatureAlgorithms",sshd_CASignatureAlgorithms) -}}
{{ body_option("ChallengeResponseAuthentication",sshd_ChallengeResponseAuthentication) -}}
{{ body_option("ChrootDirectory",sshd_ChrootDirectory) -}}
{{ body_option("Ciphers",sshd_Ciphers) -}}
{{ body_option("ClientAliveCountMax",sshd_ClientAliveCountMax) -}}
{{ body_option("ClientAliveInterval",sshd_ClientAliveInterval) -}}
{{ body_option("Compression",sshd_Compression) -}}
{{ body_option("DebianBanner",sshd_DebianBanner) -}}
{{ body_option("DenyGroups",sshd_DenyGroups) -}}
{{ body_option("DenyUsers",sshd_DenyUsers) -}}
{{ body_option("DisableForwarding",sshd_DisableForwarding) -}}
{{ body_option("ExposeAuthInfo",sshd_ExposeAuthInfo) -}}
{{ body_option("FingerprintHash",sshd_FingerprintHash) -}}
{{ body_option("ForceCommand",sshd_ForceCommand) -}}
{{ body_option("GatewayPorts",sshd_GatewayPorts) -}}
{{ body_option("GSSAPIAuthentication",sshd_GSSAPIAuthentication) -}}
{{ body_option("GSSAPICleanupCredentials",sshd_GSSAPICleanupCredentials) -}}
{{ body_option("GSSAPIKeyExchange",sshd_GSSAPIKeyExchange) -}}
{{ body_option("GSSAPIKexAlgorithms",sshd_GSSAPIKexAlgorithms) -}}
{{ body_option("GSSAPIStoreCredentialsOnRekey",sshd_GSSAPIStoreCredentialsOnRekey) -}}
{{ body_option("GSSAPIStrictAcceptorCheck",sshd_GSSAPIStrictAcceptorCheck) -}}
{{ body_option("HPNBufferSize",sshd_HPNBufferSize) -}}
{{ body_option("HPNDisabled",sshd_HPNDisabled) -}}
{{ body_option("HostCertificate",sshd_HostCertificate) -}}
{{ body_option("HostKeyAgent",sshd_HostKeyAgent) -}}
{{ body_option("HostKeyAlgorithms",sshd_HostKeyAlgorithms) -}}
{{ body_option("HostbasedAcceptedKeyTypes",sshd_HostbasedAcceptedKeyTypes) -}}
{{ body_option("HostbasedAuthentication",sshd_HostbasedAuthentication) -}}
{{ body_option("HostbasedUsesNameFromPacketOnly",sshd_HostbasedUsesNameFromPacketOnly) -}}
{{ body_option("Include",sshd_Include) -}}
{{ body_option("IPQoS",sshd_IPQoS) -}}
{{ body_option("IgnoreRhosts",sshd_IgnoreRhosts) -}}
{{ body_option("IgnoreUserKnownHosts",sshd_IgnoreUserKnownHosts) -}}
{{ body_option("KbdInteractiveAuthentication",sshd_KbdInteractiveAuthentication) -}}
{{ body_option("KerberosAuthentication",sshd_KerberosAuthentication) -}}
{{ body_option("KerberosGetAFSToken",sshd_KerberosGetAFSToken) -}}
{{ body_option("KerberosOrLocalPasswd",sshd_KerberosOrLocalPasswd) -}}
{{ body_option("KerberosTicketCleanup",sshd_KerberosTicketCleanup) -}}
{{ body_option("KexAlgorithms",sshd_KexAlgorithms) -}}
{{ body_option("KeyRegenerationInterval",sshd_KeyRegenerationInterval) -}}
{{ body_option("LogLevel",sshd_LogLevel) -}}
{{ body_option("LoginGraceTime",sshd_LoginGraceTime) -}}
{{ body_option("MACs",sshd_MACs) -}}
{{ body_option("MaxAuthTries",sshd_MaxAuthTries) -}}
{{ body_option("MaxSessions",sshd_MaxSessions) -}}
{{ body_option("MaxStartups",sshd_MaxStartups) -}}
{{ body_option("NoneEnabled",sshd_NoneEnabled) -}}
{{ body_option("PasswordAuthentication",sshd_PasswordAuthentication) -}}
{{ body_option("PermitEmptyPasswords",sshd_PermitEmptyPasswords) -}}
{{ body_option("PermitListen",sshd_PermitListen) -}}
{{ body_option("PermitOpen",sshd_PermitOpen) -}}
{{ body_option("PermitRootLogin",sshd_PermitRootLogin) -}}
{{ body_option("PermitTTY",sshd_PermitTTY) -}}
{{ body_option("PermitTunnel",sshd_PermitTunnel) -}}
{{ body_option("PermitUserEnvironment",sshd_PermitUserEnvironment) -}}
{{ body_option("PermitUserRC",sshd_PermitUserRC) -}}
{{ body_option("PidFile",sshd_PidFile) -}}
{{ body_option("PrintLastLog",sshd_PrintLastLog) -}}
{{ body_option("PrintMotd",sshd_PrintMotd) -}}
{{ body_option("PubkeyAcceptedKeyTypes",sshd_PubkeyAcceptedKeyTypes) -}}
{{ body_option("PubkeyAuthOptions",sshd_PubkeyAuthOptions) -}}
{{ body_option("PubkeyAuthentication",sshd_PubkeyAuthentication) -}}
{{ body_option("RSAAuthentication",sshd_RSAAuthentication) -}}
{{ body_option("RekeyLimit",sshd_RekeyLimit) -}}
{{ body_option("RevokedKeys",sshd_RevokedKeys) -}}
{{ body_option("RDomain",sshd_RDomain) -}}
{{ body_option("RhostsRSAAuthentication",sshd_RhostsRSAAuthentication) -}}
{{ body_option("SecurityKeyProvider",sshd_SecurityKeyProvider) -}}
{{ body_option("SetEnv",sshd_SetEnv) -}}
{{ body_option("ServerKeyBits",sshd_ServerKeyBits) -}}
{{ body_option("StreamLocalBindMask",sshd_StreamLocalBindMask) -}}
{{ body_option("StreamLocalBindUnlink",sshd_StreamLocalBindUnlink) -}}
{{ body_option("StrictModes",sshd_StrictModes) -}}
{{ body_option("Subsystem",sshd_Subsystem) -}}
{{ body_option("SyslogFacility",sshd_SyslogFacility) -}}
{{ body_option("TCPKeepAlive",sshd_TCPKeepAlive) -}}
{{ body_option("TcpRcvBufPoll",sshd_TcpRcvBufPoll) -}}
{{ body_option("TrustedUserCAKeys",sshd_TrustedUserCAKeys) -}}
{{ body_option("UseDNS",sshd_UseDNS) -}}
{{ body_option("UseLogin",sshd_UseLogin) -}}
{{ body_option("UsePAM",sshd_UsePAM) -}}
{{ body_option("UsePrivilegeSeparation",sshd_UsePrivilegeSeparation) -}}
{{ body_option("VersionAddendum",sshd_VersionAddendum) -}}
{{ body_option("X11DisplayOffset",sshd_X11DisplayOffset) -}}
{{ body_option("X11MaxDisplays",sshd_X11MaxDisplays) -}}
{{ body_option("X11Forwarding",sshd_X11Forwarding) -}}
{{ body_option("X11UseLocalhost",sshd_X11UseLocalhost) -}}
{{ body_option("XAuthLocation",sshd_XAuthLocation) -}}
{% if sshd['Match'] is defined %}
{{ match_iterate_block(sshd['Match']) -}}
{% endif %}
{% if sshd_match is defined %}
{{ match_iterate_block(sshd_match) -}}
{% endif %}
{% if sshd_match_1 is defined %}
{{ match_block(sshd_match_1) -}}
{% endif %}
{% if sshd_match_2 is defined %}
{{ match_block(sshd_match_2) -}}
{% endif %}
{% if sshd_match_3 is defined %}
{{ match_block(sshd_match_3) -}}
{% endif %}
{% if sshd_match_4 is defined %}
{{ match_block(sshd_match_4) -}}
{% endif %}
{% if sshd_match_5 is defined %}
{{ match_block(sshd_match_5) -}}
{% endif %}
{% if sshd_match_6 is defined %}
{{ match_block(sshd_match_6) -}}
{% endif %}
{% if sshd_match_7 is defined %}
{{ match_block(sshd_match_7) -}}
{% endif %}
{% if sshd_match_8 is defined %}
{{ match_block(sshd_match_8) -}}
{% endif %}
{% if sshd_match_9 is defined %}
{{ match_block(sshd_match_9) -}}
{% endif %}

View File

@ -0,0 +1,10 @@
# {{ ansible_managed }}
{% if __sshd_sysconfig_supports_crypto_policy %}
{% if sshd_sysconfig_override_crypto_policy == true %}
CRYPTO_POLICY=
{% endif %}
{% endif %}
{% if __sshd_sysconfig_supports_use_strong_rng %}
SSH_USE_STRONG_RNG={{ sshd_sysconfig_use_strong_rng }}
{% endif %}

View File

@ -0,0 +1 @@
localhost

View File

View File

@ -0,0 +1 @@
../../

View File

@ -0,0 +1,92 @@
---
- hosts: all
tasks:
- name: Configure alternative sshd_config file
include_role:
name: ansible-sshd
vars:
# just anything -- will not get processed by sshd
sshd_config_file: /etc/ssh/sshd_config_custom
sshd_skip_defaults: true
sshd:
AcceptEnv: LANG
Banner: /etc/issue
Ciphers: aes256-gcm@openssh.com
sshd_Compression: no
- name: Configure second alternative sshd_config file
include_role:
name: ansible-sshd
vars:
# just anything -- will not get processed by sshd
sshd_config_file: /etc/ssh/sshd_config_custom_second
sshd_skip_defaults: true
sshd:
Banner: /etc/issue2
Ciphers: aes128-gcm@openssh.com
sshd_MaxStartups: 100
- name: Now configure the main sshd_config file
include_role:
name: ansible-sshd
vars:
sshd:
Banner: /etc/issue
Ciphers: aes128-ctr
HostKey:
- /tmp/ssh_host_ecdsa_key
sshd_PasswordAuthentication: no
- name: Verify the options are correctly set
vars:
main_sshd_config: >-
{{
"/etc/ssh/sshd_config.d/00-ansible_system_role.conf"
if ansible_facts['distribution'] == 'Fedora'
else "/etc/ssh/sshd_config"
}}
block:
- meta: flush_handlers
- name: Print current configuration file
slurp:
src: /etc/ssh/sshd_config_custom
register: config
- name: Print second configuration file
slurp:
src: /etc/ssh/sshd_config_custom_second
register: config2
- name: Print the main configuration file
slurp:
src: "{{ main_sshd_config }}"
register: config3
- name: Check content of first configuration file
assert:
that:
- "'AcceptEnv LANG' in config.content | b64decode"
- "'Banner /etc/issue' in config.content | b64decode"
- "'Ciphers aes256-gcm@openssh.com' in config.content | b64decode"
- "'HostKey' not in config.content | b64decode"
- "'Compression no' in config.content | b64decode"
- "'MaxStartups 100' not in config.content | b64decode"
- name: Check content of second configuration file
assert:
that:
- "'Banner /etc/issue2' in config2.content | b64decode"
- "'Ciphers aes128-gcm@openssh.com' in config2.content | b64decode"
- "'HostKey' not in config2.content | b64decode"
- "'MaxStartups 100' in config2.content | b64decode"
- "'Compression no' not in config2.content | b64decode"
- name: Check content of the main configuration file
assert:
that:
- "'Banner /etc/issue' in config3.content | b64decode"
- "'Ciphers aes128-ctr' in config3.content | b64decode"
- "'HostKey /tmp/ssh_host_ecdsa_key' in config3.content | b64decode"
- "'PasswordAuthentication no' in config3.content | b64decode"
- "'MaxStartups 100' not in config3.content | b64decode"
- "'Compression no' not in config3.content | b64decode"
tags: tests::verify

View File

@ -0,0 +1,4 @@
---
- hosts: all
roles:
- ansible-sshd

View File

@ -0,0 +1,6 @@
---
- hosts: all
tasks:
- name: "Configure sshd"
include_role:
name: ansible-sshd

View File

@ -0,0 +1,70 @@
---
- hosts: all
tasks:
- name: Remove host key before the test
file:
path: /tmp/ssh_host_ed25519_key
state: absent
- name: Ensure group 'nobody' exists
group:
name: nobody
- name: Ensure the user 'nobody' exists
user:
name: nobody
group: nobody
comment: nobody
create_home: no
shell: /sbin/nologin
- name: Configure sshd with alternative host keys
include_role:
name: ansible-sshd
vars:
# very BAD example
sshd_hostkey_owner: "nobody"
sshd_hostkey_group: "nobody"
sshd_hostkey_mode: "0664"
sshd:
HostKey:
- /tmp/ssh_host_ed25519_key
- name: Verify the options are correctly set
vars:
main_sshd_config: >-
{{
"/etc/ssh/sshd_config.d/00-ansible_system_role.conf"
if ansible_facts['distribution'] == 'Fedora'
else "/etc/ssh/sshd_config"
}}
block:
- meta: flush_handlers
- name: Print current configuration file
slurp:
src: "{{ main_sshd_config }}"
register: config
- stat:
path: /tmp/ssh_host_ed25519_key
register: privkey
- stat:
path: /tmp/ssh_host_ed25519_key.pub
register: pubkey
- name: Check the options are in configuration file
assert:
that:
- "'HostKey /tmp/ssh_host_ed25519_key' in config.content | b64decode"
- name: Check the generated host key has requested properties
assert:
that:
- privkey.stat.exists
- privkey.stat.gr_name == 'nobody'
- privkey.stat.pw_name == 'nobody'
- privkey.stat.mode == '0664'
- pubkey.stat.exists
tags: tests::verify

View File

@ -0,0 +1,33 @@
---
- hosts: all
tasks:
- name: Configure sshd with missing host keys and prevent their creation
block:
- name: Configure missing hostkey
include_role:
name: ansible-sshd
vars:
sshd_verify_hostkeys: []
sshd:
HostKey:
- /tmp/missing_ssh_host_rsa_key
register: role_result
- name: unreachable task
fail:
msg: UNREACH
rescue:
- name: Check that we failed in the role
assert:
that:
- ansible_failed_result.msg != 'UNREACH'
- not role_result.changed
msg: "Role has not failed when it should have"
- name: Make sure service is still running
service:
name: sshd
state: started
register: result
failed_when: result.changed

View File

@ -0,0 +1,81 @@
---
- hosts: all
tasks:
- name: Configure sshd
include_role:
name: ansible-sshd
vars:
# For Fedora containers, we need to make sure we have keys for sshd -T below
sshd_verify_hostkeys:
- /etc/ssh/ssh_host_rsa_key
sshd:
Match:
- Condition: "User xusers"
X11Forwarding: yes
Banner: /tmp/xusers-banner
sshd_match:
- Condition: "User bot"
AllowTcpForwarding: no
Banner: /tmp/bot-banner
sshd_match_1:
- Condition: "User sftponly"
ForceCommand: "internal-sftp"
ChrootDirectory: "/var/uploads/"
sshd_match_2:
- Condition: "User root"
PasswordAuthentication: no
PermitTunnel: yes
- name: Verify the options are correctly set
vars:
main_sshd_config: >-
{{
"/etc/ssh/sshd_config.d/00-ansible_system_role.conf"
if ansible_facts['distribution'] == 'Fedora'
else "/etc/ssh/sshd_config"
}}
block:
- meta: flush_handlers
- name: List effective configuration using sshd -T for xusers
command: sshd -T -C user=xusers,addr=127.0.0.1,host=example.com
register: xusers_effective
- name: List effective configuration using sshd -T for bot
command: sshd -T -C user=bot,addr=127.0.0.1,host=example.com
register: bot_effective
- name: List effective configuration using sshd -T for sftponly
command: sshd -T -C user=sftponly,addr=127.0.0.1,host=example.com
register: sftponly_effective
- name: List effective configuration using sshd -T for root
command: sshd -T -C user=root,addr=127.0.0.1,host=example.com
register: root_effective
- name: Print current configuration file
slurp:
src: "{{ main_sshd_config }}"
register: config
- name: Check the options are effective
# note, the options are in lower-case here
assert:
that:
- "'x11forwarding yes' in xusers_effective.stdout"
- "'banner /tmp/xusers-banner' in xusers_effective.stdout"
- "'allowtcpforwarding no' in bot_effective.stdout"
- "'banner /tmp/bot-banner' in bot_effective.stdout"
- "'forcecommand internal-sftp' in sftponly_effective.stdout"
- "'chrootdirectory /var/uploads/' in sftponly_effective.stdout"
- "'passwordauthentication no' in root_effective.stdout"
- "'permittunnel yes' in root_effective.stdout"
- name: Check the options are in configuration file
assert:
that:
- "'Match User xusers' in config.content | b64decode"
- "'Match User bot' in config.content | b64decode"
- "'Match User sftponly' in config.content | b64decode"
- "'Match User root' in config.content | b64decode"
tags: tests::verify

View File

@ -0,0 +1,79 @@
---
- hosts: all
tasks:
- name: Configure sshd
include_role:
name: ansible-sshd
vars:
# For Fedora containers, we need to make sure we have keys for sshd -T below
sshd_verify_hostkeys:
- /etc/ssh/ssh_host_rsa_key
sshd:
Match:
- Condition: "User xusers"
X11Forwarding: yes
Banner: /tmp/xusers-banner
- Condition: "User bot"
AllowTcpForwarding: no
Banner: /tmp/bot-banner
sshd_match:
- Condition: "User sftponly"
ForceCommand: "internal-sftp"
ChrootDirectory: "/var/uploads/"
- Condition: "User root"
PasswordAuthentication: no
PermitTunnel: yes
- name: Verify the options are correctly set
vars:
main_sshd_config: >-
{{
"/etc/ssh/sshd_config.d/00-ansible_system_role.conf"
if ansible_facts['distribution'] == 'Fedora'
else "/etc/ssh/sshd_config"
}}
block:
- meta: flush_handlers
- name: List effective configuration using sshd -T for xusers
command: sshd -T -C user=xusers,addr=127.0.0.1,host=example.com
register: xusers_effective
- name: List effective configuration using sshd -T for bot
command: sshd -T -C user=bot,addr=127.0.0.1,host=example.com
register: bot_effective
- name: List effective configuration using sshd -T for sftponly
command: sshd -T -C user=sftponly,addr=127.0.0.1,host=example.com
register: sftponly_effective
- name: List effective configuration using sshd -T for root
command: sshd -T -C user=root,addr=127.0.0.1,host=example.com
register: root_effective
- name: Print current configuration file
slurp:
src: "{{ main_sshd_config }}"
register: config
- name: Check the options are effective
# note, the options are in lower-case here
assert:
that:
- "'x11forwarding yes' in xusers_effective.stdout"
- "'banner /tmp/xusers-banner' in xusers_effective.stdout"
- "'allowtcpforwarding no' in bot_effective.stdout"
- "'banner /tmp/bot-banner' in bot_effective.stdout"
- "'forcecommand internal-sftp' in sftponly_effective.stdout"
- "'chrootdirectory /var/uploads/' in sftponly_effective.stdout"
- "'passwordauthentication no' in root_effective.stdout"
- "'permittunnel yes' in root_effective.stdout"
- name: Check the options are in configuration file
assert:
that:
- "'Match User xusers' in config.content | b64decode"
- "'Match User bot' in config.content | b64decode"
- "'Match User sftponly' in config.content | b64decode"
- "'Match User root' in config.content | b64decode"
tags: tests::verify

View File

@ -0,0 +1,44 @@
---
- hosts: all
tasks:
- name: Configure sshd
include_role:
name: ansible-sshd
vars:
sshd:
AcceptEnv: LANG
Banner: /etc/issue
Ciphers: aes256-gcm@openssh.com
Subsystem: "sftp internal-sftp"
sshd_config_file: /etc/ssh/sshd_config
- name: Verify the options are correctly set
block:
- meta: flush_handlers
- name: List effective configuration using sshd -T
command: sshd -T
register: runtime
- name: Print current configuration file
slurp:
src: /etc/ssh/sshd_config
register: config
- name: Check the options are effective
# note, the options are in lower-case here
assert:
that:
- "'acceptenv LANG' in runtime.stdout"
- "'banner /etc/issue' in runtime.stdout"
- "'ciphers aes256-gcm@openssh.com' in runtime.stdout"
- "'subsystem sftp internal-sftp' in runtime.stdout"
- name: Check the options are in configuration file
assert:
that:
- "'AcceptEnv LANG' in config.content | b64decode"
- "'Banner /etc/issue' in config.content | b64decode"
- "'Ciphers aes256-gcm@openssh.com' in config.content | b64decode"
- "'Subsystem sftp internal-sftp' in config.content | b64decode"
tags: tests::verify

View File

@ -0,0 +1,50 @@
---
- hosts: all
tasks:
- name: Configure sshd with uncommon options, making sure it keeps running
block:
- name: Configure ssh with unsupported options
include_role:
name: ansible-sshd
vars:
sshd:
# Unsupported in new versions, but ignored ?
Protocol: 1
UsePrivilegeSeparation: no
UseLogin: yes
# Debian only
DebianBanner: /etc/motd
# Used in FreeBSD ?
VersionAddendum: FreeBSD-20180909
# HPN only
HPNDisabled: yes
HPNBufferSize: 2MB
TcpRcvBufPoll: yes
NoneEnabled: yes
# some builds might be without kerberos/GSSAPI
KerberosAuthentication: yes
GSSAPIStoreCredentialsOnRekey: yes
# SSHv1 options
KeyRegenerationInterval: 1h
ServerKeyBits: 1024
# This one is pretty new, but works on OpenBSD only
RDomain: 2
register: role_result
- name: unreachable task
fail:
msg: UNREACH
rescue:
- name: Check that we failed in the role
assert:
that:
- ansible_failed_result.msg != 'UNREACH'
- not role_result.changed
msg: "Role has not failed when it should have"
- name: Make sure service is still running
service:
name: sshd
state: started
register: result
failed_when: result.changed

View File

@ -0,0 +1,41 @@
---
- hosts: all
tasks:
- name: Configure sshd
include_role:
name: ansible-sshd
vars:
sshd_sysconfig: true
sshd_sysconfig_override_crypto_policy: true
sshd_sysconfig_use_strong_rng: 32
- name: Verify the options are correctly set
block:
- meta: flush_handlers
- name: Print current configuration file
slurp:
src: /etc/sysconfig/sshd
register: config
- name: Check the crypto policies is overridden in RHEL 8
assert:
that:
- "'CRYPTO_POLICY=' in config.content | b64decode"
# these are string variants in default configuration file
- "'# CRYPTO_POLICY=' not in config.content | b64decode"
when:
- ansible_facts['os_family'] == "RedHat"
- ansible_facts['distribution_major_version'] == "8"
- name: Check the RNG options are in configuration file
assert:
that:
- "'SSH_USE_STRONG_RNG=32' in config.content | b64decode"
# these are string variants in default configuration file
- "'SSH_USE_STRONG_RNG=0' not in config.content | b64decode"
- "'# SSH_USE_STRONG_RNG=1' not in config.content | b64decode"
when:
- ansible_facts['os_family'] == "RedHat"
- ansible_facts['distribution'] != 'Fedora'
tags: tests::verify

14
roles/sshd/vars/AIX.yml Normal file
View File

@ -0,0 +1,14 @@
---
sshd_config_mode: '0644'
# sshd is not installed by yum / AIX toolbox for Linux.
# You'll need to manually install them using AIX Web Download Packs.
sshd_packages: []
sshd_sftp_server: /usr/sbin/sftp-server
sshd_config_group: system
__sshd_defaults:
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
sshd_install_service: no
sshd_manage_service: no
sshd_allow_reload: yes

View File

@ -0,0 +1,23 @@
---
sshd_config_mode: '0644'
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
__sshd_defaults:
SyslogFacility: AUTHPRIV
PermitRootLogin: forced-commands-only
AuthorizedKeysFile: .ssh/authorized_keys
PasswordAuthentication: no
ChallengeResponseAuthentication: no
UsePAM: yes
X11Forwarding: yes
PrintLastLog: yes
UsePrivilegeSeparation: sandbox
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes

View File

@ -0,0 +1 @@
Archlinux.yml

View File

@ -0,0 +1,11 @@
---
sshd_packages:
- openssh
sshd_sftp_server: /usr/lib/ssh/sftp-server
__sshd_defaults:
AuthorizedKeysFile: .ssh/authorized_keys
ChallengeResponseAuthentication: no
PrintMotd: no
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,13 @@
---
# There is no package manager in CoreOS
sshd_packages: []
sshd_service: sshd
sshd_sftp_server: internal-sftp
__sshd_defaults:
Subsystem: "sftp {{ sshd_sftp_server }}"
ClientAliveInterval: 180
UseDNS: no
UsePAM: yes
PrintLastLog: no
PrintMotd: no
__sshd_os_supported: yes

View File

@ -0,0 +1,36 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
UsePrivilegeSeparation: yes
KeyRegenerationInterval: 3600
ServerKeyBits: 768
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: yes
StrictModes: yes
RSAAuthentication: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
RhostsRSAAuthentication: no
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,34 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_ed25519_key
HostKeyAlgorithms: ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa,ssh-ed25519-cert-v01@openssh.com
KexAlgorithms: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group-exchange-sha256
MACs: umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: without-password
StrictModes: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,38 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation: yes
KeyRegenerationInterval: 3600
ServerKeyBits: 1024
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: without-password
StrictModes: yes
RSAAuthentication: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
RhostsRSAAuthentication: no
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,34 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation: yes
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: without-password
StrictModes: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,13 @@
---
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
# Fedora 32 ships with drop-in directory support so we touch
# just included file with highest priority by default and have
# empty defaults
sshd_config_file: /etc/ssh/sshd_config.d/00-ansible_system_role.conf
__sshd_defaults:
__sshd_os_supported: yes
sshd_hostkey_group: ssh_keys
sshd_hostkey_mode: "0640"

View File

@ -0,0 +1,28 @@
---
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
__sshd_defaults:
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
SyslogFacility: AUTHPRIV
AuthorizedKeysFile: .ssh/authorized_keys
PasswordAuthentication: yes
ChallengeResponseAuthentication: no
GSSAPIAuthentication: yes
GSSAPICleanupCredentials: no
UsePAM: yes
X11Forwarding: yes
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
__sshd_sysconfig_supports_crypto_policy: true
sshd_hostkey_group: ssh_keys
sshd_hostkey_mode: "0640"

View File

@ -0,0 +1,5 @@
---
sshd_config_group: wheel
sshd_config_mode: "0644"
sshd_sftp_server: /usr/libexec/sftp-server
__sshd_os_supported: yes

View File

@ -0,0 +1,32 @@
---
sshd_packages:
- net-misc/openssh
sshd_sftp_server: /usr/lib64/misc/sftp-server
__sshd_defaults:
Subsystem: "sftp {{ sshd_sftp_server }}"
# Replace tcp keepalive with unspoofable keepalive
TCPKeepAlive: no
ClientAliveInterval: 300
ClientAliveCountMax: 2
# Secure cipher and algorithm settings
HostKey:
- /etc/ssh/ssh_host_ed25519_key
- /etc/ssh/ssh_host_rsa_key
HostKeyAlgorithms: "ssh-ed25519,ssh-rsa,ssh-ed25519-cert-v01@openssh.com"
KexAlgorithms: "curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256"
Ciphers: "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
MACs: "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com"
AuthorizedKeysFile: .ssh/authorized_keys
# Security settings
PasswordAuthentication: no
ChallengeResponseAuthentication: no
PermitRootLogin: no
# Login settings
UsePAM: yes
PrintMotd: no
PrintLastLog: yes
# Disable most forwarding types for more security
AllowAgentForwarding: no
AllowTcpForwarding: no
AllowStreamLocalForwarding: no
__sshd_os_supported: yes

View File

@ -0,0 +1,9 @@
---
sshd_config_group: wheel
sshd_config_mode: "0600"
sshd_sftp_server: /usr/libexec/sftp-server
__sshd_defaults:
AuthorizedKeysFile: .ssh/authorized_keys
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
__sshd_manage_var_run: no

View File

@ -0,0 +1,24 @@
---
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
__sshd_defaults:
Protocol: 2
SyslogFacility: AUTHPRIV
PasswordAuthentication: yes
ChallengeResponseAuthentication: no
GSSAPIAuthentication: yes
GSSAPICleanupCredentials: yes
UsePAM: yes
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
X11Forwarding: yes
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
__sshd_sysconfig_supports_use_strong_rng: true
sshd_hostkey_group: ssh_keys
sshd_hostkey_mode: "0640"

View File

@ -0,0 +1,31 @@
---
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
__sshd_defaults:
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
SyslogFacility: AUTHPRIV
AuthorizedKeysFile: .ssh/authorized_keys
PasswordAuthentication: yes
ChallengeResponseAuthentication: no
GSSAPIAuthentication: yes
GSSAPICleanupCredentials: no
# Note that UsePAM: no is not supported under RHEL/CentOS. See
# https://github.com/willshersystems/ansible-sshd/pull/51#issuecomment-287333218
UsePAM: yes
X11Forwarding: yes
UsePrivilegeSeparation: sandbox
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
__sshd_sysconfig_supports_use_strong_rng: true
sshd_hostkey_group: ssh_keys
sshd_hostkey_mode: "0640"

View File

@ -0,0 +1,32 @@
---
sshd_packages:
- openssh
- openssh-server
sshd_sftp_server: /usr/libexec/openssh/sftp-server
__sshd_defaults:
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
SyslogFacility: AUTHPRIV
AuthorizedKeysFile: .ssh/authorized_keys
PasswordAuthentication: yes
ChallengeResponseAuthentication: no
GSSAPIAuthentication: yes
GSSAPICleanupCredentials: no
# Note that UsePAM: no is not supported under RHEL/CentOS. See
# https://github.com/willshersystems/ansible-sshd/pull/51#issuecomment-287333218
UsePAM: yes
X11Forwarding: yes
PrintMotd: no
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes
__sshd_sysconfig_supports_use_strong_rng: true
__sshd_sysconfig_supports_crypto_policy: true
sshd_hostkey_group: ssh_keys
sshd_hostkey_mode: "0640"

25
roles/sshd/vars/Suse.yml Normal file
View File

@ -0,0 +1,25 @@
---
sshd_packages:
- openssh
sshd_sftp_server: /usr/lib/ssh/sftp-server
__sshd_defaults:
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
SyslogFacility: AUTH
AuthorizedKeysFile: .ssh/authorized_keys
PasswordAuthentication: yes
ChallengeResponseAuthentication: no
GSSAPIAuthentication: yes
GSSAPICleanupCredentials: no
UsePAM: yes
X11Forwarding: yes
UsePrivilegeSeparation: sandbox
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL LANGUAGE
- XMODIFIERS
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes

View File

@ -0,0 +1,36 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
UsePrivilegeSeparation: yes
KeyRegenerationInterval: 3600
ServerKeyBits: 768
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: yes
StrictModes: yes
RSAAuthentication: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
RhostsRSAAuthentication: no
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,38 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation: yes
KeyRegenerationInterval: 3600
ServerKeyBits: 1024
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: without-password
StrictModes: yes
RSAAuthentication: yes
PubkeyAuthentication: yes
IgnoreRhosts: yes
RhostsRSAAuthentication: no
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
__sshd_os_supported: yes

View File

@ -0,0 +1,40 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
Port: 22
Protocol: 2
HostKey:
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation: yes
KeyRegenerationInterval: 3600
ServerKeyBits: 1024
SyslogFacility: AUTH
LogLevel: INFO
LoginGraceTime: 120
PermitRootLogin: prohibit-password
StrictModes: yes
RSAAuthentication: yes
PubkeyAuthentication: yes
AuthorizedKeysFile: "%h/.ssh/authorized_keys"
IgnoreRhosts: yes
RhostsRSAAuthentication: no
HostbasedAuthentication: no
PermitEmptyPasswords: no
ChallengeResponseAuthentication: no
X11Forwarding: yes
X11DisplayOffset: 10
PrintMotd: no
PrintLastLog: yes
TCPKeepAlive: yes
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
UsePAM: yes
UseDNS: no
__sshd_os_supported: yes

View File

@ -0,0 +1,15 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
PasswordAuthentication: no
ChallengeResponseAuthentication: no
UsePAM: yes
X11Forwarding: yes
PrintMotd: no
AcceptEnv: LANG LC_*
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes

View File

@ -0,0 +1,14 @@
---
sshd_service: ssh
sshd_packages:
- openssh-server
- openssh-sftp-server
sshd_config_mode: "0644"
__sshd_defaults:
ChallengeResponseAuthentication: no
UsePAM: yes
X11Forwarding: yes
PrintMotd: no
AcceptEnv: LANG LC_*
Subsystem: "sftp /usr/lib/openssh/sftp-server"
__sshd_os_supported: yes

View File

@ -0,0 +1 @@
---

View File

@ -0,0 +1,14 @@
---
sshd_packages:
- openssh
sshd_sftp_server: /usr/lib/ssh/sftp-server
__sshd_defaults:
AuthorizedKeysFile: .ssh/authorized_keys
UsePAM: yes
X11Forwarding: yes
AcceptEnv:
- LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
- LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
- LC_IDENTIFICATION LC_ALL
Subsystem: "sftp {{ sshd_sftp_server }}"
__sshd_os_supported: yes

View File

@ -10,6 +10,20 @@
tags: [ ansible, common ]
- role: adminuser
tags: [ adminuser, common ]
- role: sshd
vars:
sshd:
AcceptEnv: "LANG LC_*"
ChallengeResponseAuthentication: no
Compression: yes
PasswordAuthentication: no
PermitRootLogin: no
PrintMotd: no
PubkeyAuthentication: yes
Subsystem: "sftp /usr/lib/openssh/sftp-server"
UsePAM: yes
X11Forwarding: no
tags: [ sshd, common ]
- role: git
vars:
git_repos: