diff --git a/.ansible-lint b/.ansible-lint index 6fcd54e..eb0ae7c 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -1,5 +1,6 @@ exclude_paths: - tests/roles/ - .tox/ + - .markdownlint.yaml skip_list: - var-naming[no-role-prefix] diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml new file mode 100644 index 0000000..13efaab --- /dev/null +++ b/.github/workflows/build_docs.yml @@ -0,0 +1,101 @@ +--- +# yamllint disable rule:line-length +name: Convert README.md to HTML and push to docs branch +on: # yamllint disable-line rule:truthy + push: + branches: + - main + paths: + - README.md + release: + types: + - published +permissions: + contents: read +jobs: + build_docs: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Ensure the docs branch + run: | + set -euxo pipefail + branch=docs + existed_in_remote=$(git ls-remote --heads origin $branch) + + if [ -z "${existed_in_remote}" ]; then + echo "Creating $branch branch" + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git checkout --orphan $branch + git reset --hard + git commit --allow-empty -m "Initializing $branch branch" + git push origin $branch + echo "Created $branch branch" + else + echo "Branch $branch already exists" + fi + + - name: Checkout the docs branch + uses: actions/checkout@v3 + with: + ref: docs + + - name: Fetch README.md and .pandoc_template.html5 template from the workflow branch + uses: actions/checkout@v3 + with: + sparse-checkout: | + README.md + .pandoc_template.html5 + sparse-checkout-cone-mode: false + path: ref_branch + - name: Set RELEASE_VERSION based on whether run on release or on push + run: | + set -euxo pipefail + if [ ${{ github.event_name }} = release ]; then + echo "RELEASE_VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV + elif [ ${{ github.event_name }} = push ]; then + echo "RELEASE_VERSION=latest" >> $GITHUB_ENV + else + echo Unsupported event + exit 1 + fi + + - name: Ensure that version and docs directories exist + run: mkdir -p ${{ env.RELEASE_VERSION }} docs + + - name: Convert README.md to HTML and save to the version directory + uses: docker://pandoc/core:latest + with: + args: >- + --from gfm --to html5 --toc --shift-heading-level-by=-1 + --template ref_branch/.pandoc_template.html5 + --output ${{ env.RELEASE_VERSION }}/README.html ref_branch/README.md + + - name: Copy latest README.html to docs/index.html for GitHub pages + if: env.RELEASE_VERSION == 'latest' + run: cp ${{ env.RELEASE_VERSION }}/README.html docs/index.html + + - name: Commit changes + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git add ${{ env.RELEASE_VERSION }}/README.html docs/index.html + git commit -m "Update README.html for ${{ env.RELEASE_VERSION }}" + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: docs diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml new file mode 100644 index 0000000..98e3c4c --- /dev/null +++ b/.github/workflows/markdownlint.yml @@ -0,0 +1,34 @@ +--- +# yamllint disable rule:line-length +name: Markdown Lint +on: # yamllint disable-line rule:truthy + pull_request: + merge_group: + branches: + - main + types: + - checks_requested + push: + branches: + - main + workflow_dispatch: +permissions: + contents: read +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + + - name: Lint README.md + uses: docker://avtodev/markdown-lint:master + with: + args: README.md + config: .markdownlint.yaml diff --git a/.github/workflows/test_converting_readme.yml b/.github/workflows/test_converting_readme.yml new file mode 100644 index 0000000..e545613 --- /dev/null +++ b/.github/workflows/test_converting_readme.yml @@ -0,0 +1,43 @@ +--- +# yamllint disable rule:line-length +name: Test converting README.md to README.html +on: # yamllint disable-line rule:truthy + pull_request: + merge_group: + branches: + - main + types: + - checks_requested + push: + branches: + - main +permissions: + contents: read +jobs: + test_converting_readme: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Update pip, git + run: | + set -euxo pipefail + sudo apt update + sudo apt install -y git + + - name: Check out code + uses: actions/checkout@v3 + + - name: Convert README.md to HTML and save to the version directory + uses: docker://pandoc/core:latest + with: + args: >- + --from gfm --to html5 --toc --shift-heading-level-by=-1 + --template .pandoc_template.html5 + --output README.html README.md + + - name: Upload README.html as an artifact + uses: actions/upload-artifact@master + with: + name: README.html + path: README.html diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..4f8a979 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,260 @@ +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time +MD001: true + +# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading +MD002: + # Heading level + level: 1 + +# MD003/heading-style/header-style - Heading style +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style - Unordered list style +MD004: + # List style + style: "consistent" + +# MD005/list-indent - Inconsistent indentation for list items at the same level +MD005: true + +# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line +MD006: true + +# MD007/ul-indent - Unordered list indentation +MD007: + # Spaces for indent + indent: 2 + # Whether to indent the first level of the list + start_indented: false + # Spaces for first level indent (when start_indented is set) + start_indent: 2 + +# MD009/no-trailing-spaces - Trailing spaces +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs - Hard tabs +MD010: + # Include code blocks + code_blocks: true + # Fenced code languages to ignore + ignore_code_languages: [] + # Number of spaces for each hard tab + spaces_per_tab: 1 + +# MD011/no-reversed-links - Reversed link syntax +MD011: true + +# MD012/no-multiple-blanks - Multiple consecutive blank lines +MD012: + # Consecutive blank lines + maximum: 1 + +# Modified for LSR +# GFM does not limit line length +# MD013/line-length - Line length +MD013: false + # # Number of characters + # # line_length: 80 + # line_length: 999 + # # Number of characters for headings + # heading_line_length: 80 + # # Number of characters for code blocks + # code_block_line_length: 80 + # # Include code blocks + # code_blocks: true + # # Include tables + # tables: true + # # Include headings + # headings: true + # # Include headings + # headers: true + # # Strict length checking + # strict: false + # # Stern length checking + # stern: false + +# MD014/commands-show-output - Dollar signs used before commands without showing output +MD014: true + +# MD018/no-missing-space-atx - No space after hash on atx style heading +MD018: true + +# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading +MD019: true + +# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading +MD020: true + +# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading +MD021: true + +# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line +MD023: true + +# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content +MD024: true + +# MD025/single-title/single-h1 - Multiple top-level headings in the same document +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation - Trailing punctuation in heading +MD026: + # Punctuation characters not allowed at end of headings + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol +MD027: true + +# MD028/no-blanks-blockquote - Blank line inside blockquote +MD028: true + +# MD029/ol-prefix - Ordered list item prefix +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space - Spaces after list markers +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines +MD031: + # Include list items + list_items: true + +# MD032/blanks-around-lists - Lists should be surrounded by blank lines +MD032: true + +# MD033/no-inline-html - Inline HTML +MD033: + # Allowed elements + allowed_elements: [] + +# MD034/no-bare-urls - Bare URL used +MD034: true + +# MD035/hr-style - Horizontal rule style +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading +MD036: + # Punctuation characters + punctuation: ".,;:!?。,;:!?" + +# MD037/no-space-in-emphasis - Spaces inside emphasis markers +MD037: true + +# MD038/no-space-in-code - Spaces inside code span elements +MD038: true + +# MD039/no-space-in-links - Spaces inside link text +MD039: true + +# MD040/fenced-code-language - Fenced code blocks should have a language specified +MD040: + # List of languages + allowed_languages: [] + # Require language only + language_only: false + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD042/no-empty-links - No empty links +MD042: true + +# Modified for LSR +# Disabling, we do not need this +# MD043/required-headings/required-headers - Required heading structure +MD043: false + # # List of headings + # headings: [] + # # List of headings + # headers: [] + # # Match case of headings + # match_case: false + +# MD044/proper-names - Proper names should have the correct capitalization +MD044: + # List of proper names + names: [] + # Include code blocks + code_blocks: true + # Include HTML elements + html_elements: true + +# MD045/no-alt-text - Images should have alternate text (alt text) +MD045: true + +# MD046/code-block-style - Code block style +MD046: + # Block style + style: "consistent" + +# MD047/single-trailing-newline - Files should end with a single newline character +MD047: true + +# MD048/code-fence-style - Code fence style +MD048: + # Code fence style + style: "consistent" + +# MD049/emphasis-style - Emphasis style should be consistent +MD049: + # Emphasis style should be consistent + style: "consistent" + +# MD050/strong-style - Strong style should be consistent +MD050: + # Strong style should be consistent + style: "consistent" + +# MD051/link-fragments - Link fragments should be valid +MD051: true + +# MD052/reference-links-images - Reference links and images should use a label that is defined +MD052: true + +# MD053/link-image-reference-definitions - Link and image reference definitions should be needed +MD053: + # Ignored definitions + ignored_definitions: + - "//" diff --git a/.pandoc_template.html5 b/.pandoc_template.html5 new file mode 100644 index 0000000..f214661 --- /dev/null +++ b/.pandoc_template.html5 @@ -0,0 +1,166 @@ +$--| GitHub HTML5 Pandoc Template" v2.2 | 2020/08/12 | pandoc v2.1.1 + + +$-------------------------------------------------------------------------> lang + + +$--============================================================================= +$-- METADATA +$--============================================================================= + + + +$-----------------------------------------------------------------------> author +$for(author-meta)$ + +$endfor$ +$-------------------------------------------------------------------------> date +$if(date-meta)$ + +$endif$ +$---------------------------------------------------------------------> keywords +$if(keywords)$ + +$endif$ +$------------------------------------------------------------------> description +$if(description)$ + +$endif$ +$------------------------------------------------------------------------> title + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ +$--=========================================================================== +$-- CSS STYLESHEETS +$--=========================================================================== +$-- Here comes the placeholder (within double braces) that will be replaced +$-- by the CSS file in the finalized template: + +$------------------------------------------------------------------------------- + +$------------------------------------------------------------------------------- +$if(quotes)$ + +$endif$ +$-------------------------------------------------------------> highlighting-css +$if(highlighting-css)$ + +$endif$ +$--------------------------------------------------------------------------> css +$for(css)$ + +$endfor$ +$-------------------------------------------------------------------------> math +$if(math)$ + $math$ +$endif$ +$------------------------------------------------------------------------------- + +$--------------------------------------------------------------> header-includes +$for(header-includes)$ + $header-includes$ +$endfor$ +$------------------------------------------------------------------------------- + + +
+$---------------------------------------------------------------> include-before +$for(include-before)$ +$include-before$ +$endfor$ +$-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IF: title +$if(title)$ +
+

$title$

+$---------------------------------------------------------------------> subtitle +$if(subtitle)$ +

$subtitle$

+$endif$ +$-----------------------------------------------------------------------> author +$for(author)$ +

$author$

+$endfor$ +$-------------------------------------------------------------------------> date +$if(date)$ +

$date$

+$endif$ +$----------------------------------------------------------------------> summary +$if(summary)$ +
+$summary$ +
+$endif$ +$------------------------------------------------------------------------------- +
+$endif$ +$--<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< END IF: title +$--------------------------------------------------------------------------> toc +$if(toc)$ +
+ +
+$endif$ +$-------------------------------------------------------------------------> body +$body$ +$----------------------------------------------------------------> include-after +$for(include-after)$ +$include-after$ +$endfor$ +$------------------------------------------------------------------------------- +
+ + diff --git a/README.md b/README.md index 342fc50..fd96745 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -OpenSSH Server -============== +# OpenSSH Server [![Ansible Lint](https://github.com/willshersystems/ansible-sshd/actions/workflows/ansible-lint.yml/badge.svg)](https://github.com/willshersystems/ansible-sshd/actions/workflows/ansible-lint.yml) [![Ansible Galaxy](http://img.shields.io/badge/galaxy-willshersystems.sshd-660198.svg?style=flat)](https://galaxy.ansible.com/willshersystems/sshd/) @@ -24,8 +23,7 @@ Ubuntu. This is not the default assigned by this module - it will set via simple password. If you need this functionality, be sure to set `sshd_PermitRootLogin yes` for those hosts. -Requirements ------------- +## Requirements Tested on: @@ -47,7 +45,6 @@ Tested on: It will likely work on other flavours and more direct support via suitable [vars/](vars/) files is welcome. - ### Optional requirements If you want to use advanced functionality of this role that can configure @@ -55,31 +52,33 @@ firewall and selinux for you, which is mostly useful when custom port is used, the role requires additional collections which are specified in `meta/collection-requirements.yml`. These are not automatically installed. You must install them like this: -``` + +```bash ansible-galaxy install -vv -r meta/collection-requirements.yml ``` For more information, see `sshd_manage_firewall` and `sshd_manage_selinux` options below. These roles are supported only on Red Hat based Linux. -Role variables ---------------- +## Role variables + +### Primary 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` +#### sshd_enable If set to *false*, the role will be completely disabled. Defaults to *true*. -* `sshd_skip_defaults` +#### 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* unless `sshd_config_namespace` is set or `sshd_config_file` points to a drop-in directory to avoid recursive include. -* `sshd_manage_service` +#### 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* @@ -87,7 +86,7 @@ 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` +#### 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 @@ -95,22 +94,22 @@ 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` +#### 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`) +* `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_manage_firewall` +#### sshd_manage_firewall If set to *true*, the the SSH port(s) will be opened in firewall. Note, this works only on Red Hat based OS. The default is *false*. @@ -119,7 +118,7 @@ NOTE: `sshd_manage_firewall` is limited to *adding* ports. It cannot be used for *removing* ports. If you want to remove ports, you will need to use the firewall system role directly. -* `sshd_manage_selinux` +#### sshd_manage_selinux If set to *true*, the the selinux will be configured to allow sshd listening on the given SSH port(s). Note, this works only on Red Hat based OS. @@ -129,7 +128,7 @@ NOTE: `sshd_manage_selinux` is limited to *adding* policy. It cannot be used for *removing* policy. If you want to remove ports, you will need to use the selinux system role directly. -* `sshd` +#### sshd A dict containing configuration. e.g. @@ -140,7 +139,7 @@ sshd: - 0.0.0.0 ``` -* `sshd_...` +#### sshd_ Simple variables can be used rather than a dict. Simple values override dict values. e.g.: @@ -160,44 +159,44 @@ sshd_ListenAddress: Renders as: -``` +```text ListenAddress 0.0.0.0 ListenAddress :: ``` -* `sshd_match`, `sshd_match_1` through `sshd_match_9` +#### sshd_match, sshd_match_1 through sshd_match_9 A list of dicts or just a dict for a Match section. Note, that these variables do not override match blocks as defined in the `sshd` dict. All of the sources will be reflected in the resulting configuration file. The use of `sshd_match_*` variant is deprecated and no longer recommended. -* `sshd_backup` +#### sshd_backup When set to *false*, the original `sshd_config` file is not backed up. Default is *true*. -* `sshd_sysconfig` +#### 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 configurations. Default is *false*. -* `sshd_sysconfig_override_crypto_policy` +#### sshd_sysconfig_override_crypto_policy In RHEL8-based systems, this can be used to override system-wide crypto policy by setting to *true*. Without this option, changes to ciphers, MACs, public key algorithms will have no effect on the resulting service in RHEL8. Defaults to *false*. -* `sshd_sysconfig_use_strong_rng` +#### sshd_sysconfig_use_strong_rng In RHEL-based systems (before RHEL9), 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` +#### 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 from @@ -208,7 +207,7 @@ When this path points to a drop-in directory (like with the variable `sshd_main_config_file`) is checked to contain a proper `Include` directive. -* `sshd_config_namespace` +#### sshd_config_namespace By default (*null*), the role defines whole content of the configuration file including system defaults. You can use this variable to invoke this role from @@ -230,12 +229,12 @@ other match blocks, to ensure they are applied regardless of the previous match blocks in the existing configuration file. This allows configuring any non-conflicting options from different roles invocations. -* `sshd_config_owner`, `sshd_config_group`, `sshd_config_mode` +#### 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_verify_hostkeys` +#### sshd_verify_hostkeys By default (*auto*), this list contains all the host keys that are present in the produced configuration file. If there are none, the OpenSSH default list @@ -247,7 +246,7 @@ able to start on the first attempt. To disable this check, set this to empty list. -* `sshd_hostkey_owner`, `sshd_hostkey_group`, `sshd_hostkey_mode` +#### sshd_hostkey_owner, sshd_hostkey_group, sshd_hostkey_mode Use these variables to set the ownership and permissions for the host keys from the above list. @@ -258,41 +257,39 @@ These variables are used by the role internals and can be used to override the defaults that correspond to each supported platform. They are not tested and generally are not needed as the role will determine them from the OS type. -* `sshd_packages` +#### sshd_packages Use this variable to override the default list of packages to install. -* `sshd_binary` +#### sshd_binary The path to the openssh executable -* `sshd_service` +#### 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_sftp_server` +#### sshd_sftp_server Default path to the sftp server binary. ### Variables Exported by the Role -* `sshd_has_run` +#### sshd_has_run This variable is set to *true* after the role was successfully executed. -Dependencies ------------- +## Dependencies None -For tests the `ansible.posix` collection is required for the `mount` role to +For tests, the `ansible.posix` collection is required for the `mount` role to emulate FIPS mode. -Example Playbook ----------------- +## 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! @@ -321,7 +318,7 @@ provides. Running it will likely break your SSH access to the server! Results in: -``` +```text # Ansible managed: ... Compression yes GSSAPIAuthentication no @@ -362,7 +359,8 @@ for example: You can just add a configuration snippet with the `sshd_config_namespace` option: -``` + +```yaml --- - hosts: all tasks: @@ -378,20 +376,20 @@ option: LS_COLORS EDITOR ``` + The following snippet will be added to the default configuration file (if not yet present): -``` + +```text # BEGIN sshd system role managed block: namespace accept-env Match all AcceptEnv LANG LS_COLORS EDITOR # END sshd system role managed block: namespace accept-env ``` - More example playbooks can be found in [`examples/`](examples/) directory. -Template Generation -------------------- +## Template Generation The [`sshd_config.j2`](templates/sshd_config.j2) and [`sshd_config_snippet.j2`](templates/sshd_config_snippet.j2) templates are @@ -401,14 +399,11 @@ to the `options_body` and/or `options_match`. To regenerate the templates, from within the `meta/` directory run: `./make_option_lists` -License -------- +## License LGPLv3 - -Authors -------- +## Authors Matt Willsher