Signed-off-by: René Jochum <rene@jochums.at>master
by values from pillar. ``pillar.example`` results in the generation | by values from pillar. ``pillar.example`` results in the generation | ||||
of the default ``sshd_config`` file on Debian Wheezy. | of the default ``sshd_config`` file on Debian Wheezy. | ||||
``openssh.known_hosts`` | |||||
----------------------- | |||||
Manages the site-wide ssh_known_hosts file and fills it with the | |||||
public SSH host keys of all minions. You can restrict the set of minions | |||||
whose keys are listed by using the pillar data ``openssh:known_hosts:target`` | |||||
and ``openssh:known_hosts:expr_form`` (those fields map directly to the | |||||
corresponding attributes of the ``mine.get`` function). | |||||
The Salt mine is used to share the public SSH host keys, you must thus | |||||
configure it accordingly on all hosts that must export their keys. Two | |||||
mine functions are required, one that exports the keys (one key per line, | |||||
as they are stored in ``/etc/ssh/ssh_host_*_key.pub``) and one that defines | |||||
the public hostname that the keys are associated to. Here's the way to | |||||
setup those functions through pillar:: | |||||
# Required for openssh.known_hosts | |||||
mine_functions: | |||||
public_ssh_host_keys: | |||||
mine_function: cmd.run | |||||
cmd: cat /etc/ssh/ssh_host_*_key.pub | |||||
public_ssh_hostname: | |||||
mine_function: grains.get | |||||
key: id | |||||
The above example assumes that the minion identifier is a valid DNS name | |||||
that can be used to connect to the host. If that's not the case, you might | |||||
want to use the ``fqdn`` grain instead of the ``id`` one. The above example | |||||
also uses the default mine function names used by this formula. If you have to | |||||
use other names, then you should indicate the names to use in pillar keys | |||||
``openssh:known_hosts:mine_keys_function`` and | |||||
``openssh:known_hosts:mine_hostname_function``. | |||||
You can also integrate alternate DNS names of the various hosts in the | |||||
ssh_known_hosts files. You just have to list all the alternate DNS names as a | |||||
list in the ``openssh:known_hosts:aliases`` pillar key. Whenever the IPv4 or | |||||
IPv6 behind one of those DNS entries matches an IPv4 or IPv6 behind the | |||||
official hostname of a minion, the alternate DNS name will be associated to the | |||||
minion's public SSH host key. | |||||
``openssh.moduli`` | |||||
----------------------- | |||||
Manages the system wide ``/etc/ssh/moduli`` file. |
{% if salt['pillar.get']('openssh:generate_' ~ keyType ~ '_keys', False) %} | {% if salt['pillar.get']('openssh:generate_' ~ keyType ~ '_keys', False) %} | ||||
ssh_generate_host_{{ keyType }}_key: | ssh_generate_host_{{ keyType }}_key: | ||||
cmd.run: | cmd.run: | ||||
{%- if salt['pillar.get']('openssh:generate_' ~ keyType ~ '_size', False) %} | |||||
{%- set keySize = salt['pillar.get']('openssh:generate_' ~ keyType ~ '_size', 4096) %} | |||||
- name: ssh-keygen -t {{ keyType }} -b {{ keySize }} -N '' -f /etc/ssh/ssh_host_{{ keyType }}_key | |||||
{%- else %} | |||||
- name: ssh-keygen -t {{ keyType }} -N '' -f /etc/ssh/ssh_host_{{ keyType }}_key | - name: ssh-keygen -t {{ keyType }} -N '' -f /etc/ssh/ssh_host_{{ keyType }}_key | ||||
{%- endif %} | |||||
- creates: /etc/ssh/ssh_host_{{ keyType }}_key | - creates: /etc/ssh/ssh_host_{{ keyType }}_key | ||||
- user: root | - user: root | ||||
{% elif salt['pillar.get']('openssh:absent_' ~ keyType ~ '_keys', False) %} | |||||
ssh_host_{{ keyType }}_key: | |||||
file.absent: | |||||
- name: /etc/ssh/ssh_host_{{ keyType }}_key | |||||
ssh_host_{{ keyType }}_key.pub: | |||||
file.absent: | |||||
- name: /etc/ssh/ssh_host_{{ keyType }}_key.pub | |||||
{% elif salt['pillar.get']('openssh:provide_' ~ keyType ~ '_keys', False) %} | {% elif salt['pillar.get']('openssh:provide_' ~ keyType ~ '_keys', False) %} | ||||
ssh_host_{{ keyType }}_key: | ssh_host_{{ keyType }}_key: | ||||
file.managed: | file.managed: |
openssh: | |||||
sshd_config: /etc/ssh/sshd_config | |||||
sshd_config_src: salt://openssh/files/sshd_config | |||||
banner: /etc/ssh/banner | |||||
banner_src: salt://openssh/files/banner | |||||
ssh_known_hosts: /etc/ssh/ssh_known_hosts | |||||
dig_pkg: dnsutils | |||||
ssh_moduli: /etc/ssh/moduli |
{# | |||||
# vi:syntax=jinja | |||||
#} | |||||
{%- set target = salt['pillar.get']('openssh:known_hosts:target', '*') -%} | |||||
{%- set expr_form = salt['pillar.get']('openssh:known_hosts:expr_form', 'glob') -%} | |||||
{%- set keys_function = salt['pillar.get']('openssh:known_hosts:mine_keys_function', 'public_ssh_host_keys') -%} | |||||
{%- set hostname_function = salt['pillar.get']('openssh:known_hosts:mine_hostname_function', 'public_ssh_hostname') -%} | |||||
{#- Lookup IP of all aliases so that when we have a matching IP, we inject the alias name | |||||
in the SSH known_hosts entry -#} | |||||
{%- set aliases = salt['pillar.get']('openssh:known_hosts:aliases', []) -%} | |||||
{%- set aliases_ips = {} -%} | |||||
{%- for alias in aliases -%} | |||||
{%- for ip in salt['dig.A'](alias) + salt['dig.AAAA'](alias) -%} | |||||
{%- do aliases_ips.setdefault(ip, []).append(alias) -%} | |||||
{%- endfor -%} | |||||
{%- endfor -%} | |||||
{#- Loop over targetted minions -#} | |||||
{%- set host_keys = salt['mine.get'](target, keys_function, expr_form=expr_form) -%} | |||||
{%- set host_names = salt['mine.get'](target, hostname_function, expr_form=expr_form) -%} | |||||
{%- for host, keys in host_keys|dictsort -%} | |||||
{%- set ip4 = salt['dig.A'](host) -%} | |||||
{%- set ip6 = salt['dig.AAAA'](host) -%} | |||||
{%- set names = [host_names.get(host, host)] -%} | |||||
{%- for ip in ip4 + ip6 -%} | |||||
{%- do names.append(ip) -%} | |||||
{%- for alias in aliases_ips.get(ip, []) -%} | |||||
{%- if alias not in names -%} | |||||
{%- do names.append(alias) -%} | |||||
{%- endif -%} | |||||
{%- endfor -%} | |||||
{%- endfor -%} | |||||
{%- for line in keys.split('\n') -%} | |||||
{%- if line -%} | |||||
{{ ','.join(names) }} {{ line }} | |||||
{% endif -%} | |||||
{%- endfor -%} | |||||
{%- endfor -%} |
# Restricting Users and Hosts | # Restricting Users and Hosts | ||||
# example: | # example: | ||||
# AllowUsers vader@10.0.0.1 maul@sproing.evil.com luke | |||||
# AllowUsers vader@10.0.0.1 maul@sproing.evil.com luke | |||||
# AllowGroups wheel staff | # AllowGroups wheel staff | ||||
# | # | ||||
# Keep in mind that using AllowUsers or AllowGroups means that anyone | # Keep in mind that using AllowUsers or AllowGroups means that anyone | ||||
# AllowGroups | # AllowGroups | ||||
{{ option('AllowGroups', '') }} | {{ option('AllowGroups', '') }} | ||||
# Specifies the available KEX (Key Exchange) algorithms. | |||||
{{ option('KexAlgorithms', 'ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1') }} | |||||
# Specifies the ciphers allowed for protocol version 2. | |||||
{{ option('Ciphers', 'aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se') }} | |||||
# Specifies the available MAC (message authentication code) algorithms. | |||||
{{ option('MACs', 'hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-sha2-256,hmac-sha2-256-96,hmac-sha2-512,hmac-sha2-512-96,hmac-ripemd160,hmac-ripemd160@openssh.com,hmac-sha1-96,hmac-md5-96') }} | |||||
{# Handling unknown in salt template options #} | {# Handling unknown in salt template options #} | ||||
{%- for keyword in sshd_config.keys() %} | {%- for keyword in sshd_config.keys() %} | ||||
{#- Matches have to be at the bottem and should be handled differently -#} | {#- Matches have to be at the bottem and should be handled differently -#} |
{% from "openssh/map.jinja" import openssh with context %} | |||||
ensure dig is available: | |||||
pkg.installed: | |||||
- name: {{ openssh.dig_pkg }} | |||||
manage ssh_known_hosts file: | |||||
file.managed: | |||||
- name: {{ openssh.ssh_known_hosts }} | |||||
- source: salt://openssh/files/ssh_known_hosts | |||||
- template: jinja | |||||
- user: root | |||||
- group: root | |||||
- mode: 644 | |||||
- require: | |||||
- pkg: ensure dig is available |
{% set openssh = salt['grains.filter_by']({ | |||||
{## Start with defaults from defaults.yaml ##} | |||||
{% import_yaml "openssh/defaults.yaml" as default_settings %} | |||||
{## | |||||
Setup variable using grains['os_family'] based logic, only add key:values here | |||||
that differ from whats in defaults.yaml | |||||
##} | |||||
{% set os_family_map = salt['grains.filter_by']({ | |||||
'Arch': { | |||||
'server': 'openssh', | |||||
'client': 'openssh', | |||||
'service': 'sshd', | |||||
}, | |||||
'Debian': { | 'Debian': { | ||||
'server': 'openssh-server', | |||||
'client': 'openssh-client', | |||||
'service': 'ssh', | |||||
'sshd_config': '/etc/ssh/sshd_config', | |||||
'sshd_config_src': 'salt://openssh/files/sshd_config', | |||||
'banner': '/etc/ssh/banner', | |||||
'banner_src': 'salt://openssh/files/banner', | |||||
'server': 'openssh-server', | |||||
'client': 'openssh-client', | |||||
'service': 'ssh', | |||||
}, | |||||
'FreeBSD': { | |||||
'service': 'sshd', | |||||
'dig_pkg': 'bind-tools', | |||||
}, | |||||
'Gentoo': { | |||||
'server': 'net-misc/openssh', | |||||
'client': 'net-misc/openssh', | |||||
'service': 'sshd', | |||||
'dig_pkg': 'net-dns/bind-tools', | |||||
}, | }, | ||||
'RedHat': { | 'RedHat': { | ||||
'server': 'openssh-server', | |||||
'client': 'openssh', | |||||
'service': 'sshd', | |||||
'sshd_config': '/etc/ssh/sshd_config', | |||||
'sshd_config_src': 'salt://openssh/files/sshd_config', | |||||
'banner': '/etc/ssh/banner', | |||||
'banner_src': 'salt://openssh/files/banner', | |||||
'server': 'openssh-server', | |||||
'client': 'openssh', | |||||
'service': 'sshd', | |||||
'dig_pkg': 'bind-utils', | |||||
}, | }, | ||||
'Suse': { | 'Suse': { | ||||
'server': 'openssh', | |||||
'client': 'openssh', | |||||
'service': 'sshd', | |||||
'sshd_config': '/etc/ssh/sshd_config', | |||||
'sshd_config_src': 'salt://openssh/files/sshd_config', | |||||
'banner': '/etc/ssh/banner', | |||||
'banner_src': 'salt://openssh/files/banner', | |||||
}, | |||||
'FreeBSD': { | |||||
'service': 'sshd', | |||||
'sshd_config': '/etc/ssh/sshd_config', | |||||
'sshd_config_src': 'salt://openssh/files/sshd_config', | |||||
'banner': '/etc/ssh/banner', | |||||
'banner_src': 'salt://openssh/files/banner', | |||||
'server': 'openssh', | |||||
'client': 'openssh', | |||||
'service': 'sshd', | |||||
'dig_pkg': 'bind-utils', | |||||
}, | }, | ||||
'Arch': { | |||||
'server': 'openssh', | |||||
'client': 'openssh', | |||||
'service': 'sshd.socket', | |||||
'sshd_config': '/etc/ssh/sshd_config', | |||||
'sshd_config_src': 'salt://openssh/files/sshd_config', | |||||
'banner': '/etc/ssh/banner', | |||||
'banner_src': 'salt://openssh/files/banner', | |||||
}, | |||||
}, merge=salt['pillar.get']('openssh:lookup')) %} | |||||
} | |||||
, grain="os_family" | |||||
, merge=salt['pillar.get']('openssh:lookup')) | |||||
%} | |||||
{## Merge the flavor_map to the default settings ##} | |||||
{% do default_settings.openssh.update(os_family_map) %} | |||||
{## Merge in openssh:lookup pillar ##} | |||||
{% set openssh = salt['pillar.get']( | |||||
'openssh', | |||||
default=default_settings.openssh, | |||||
merge=True | |||||
) | |||||
%} | |||||
{% from "openssh/map.jinja" import openssh with context %} | |||||
{% if salt['pillar.get']('openssh:moduli', False) %} | |||||
ssh_moduli: | |||||
file.managed: | |||||
- name: {{ openssh.ssh_moduli }} | |||||
- contents_pillar: openssh:moduli | |||||
{% endif %} |
HostbasedAuthentication: 'no' | HostbasedAuthentication: 'no' | ||||
PermitEmptyPasswords: 'no' | PermitEmptyPasswords: 'no' | ||||
ChallengeResponseAuthentication: 'no' | ChallengeResponseAuthentication: 'no' | ||||
AuthenticationMethods 'publickey,keyboard-interactive' | |||||
AuthenticationMethods: 'publickey,keyboard-interactive' | |||||
X11Forwarding: 'yes' | X11Forwarding: 'yes' | ||||
X11DisplayOffset: 10 | X11DisplayOffset: 10 | ||||
PrintMotd: 'no' | PrintMotd: 'no' | ||||
DenyUsers: 'yoda chewbaca@112.10.21.1' | DenyUsers: 'yoda chewbaca@112.10.21.1' | ||||
AllowGroups: 'wheel staff imperial' | AllowGroups: 'wheel staff imperial' | ||||
DenyGroups: 'rebel' | DenyGroups: 'rebel' | ||||
Deny | |||||
matches: | matches: | ||||
sftp_chroot: | sftp_chroot: | ||||
type: | type: | ||||
X11Forwarding: no | X11Forwarding: no | ||||
AllowTcpForwarding: no | AllowTcpForwarding: no | ||||
ForceCommand: internal-sftp | ForceCommand: internal-sftp | ||||
# Check `man sshd_config` for supported KexAlgorithms, Ciphers and MACs first. | |||||
KexAlgorithms: 'diffie-hellman-group14-sha1,diffie-hellman-group1-sha1' | |||||
Ciphers: 'aes128-ctr,aes256-ctr' | |||||
MACs: 'hmac-sha1' | |||||
openssh: | openssh: | ||||
auth: | auth: | ||||
joe: | |||||
- name: JOE_VALID_SSH_PUBLIC_KEY | |||||
joe-valid-ssh-key-desktop: | |||||
- user: joe | |||||
present: True | present: True | ||||
enc: ssh-rsa | enc: ssh-rsa | ||||
comment: main key | |||||
- name: JOE_NON_VALID_SSH_PUBLIC_KEY | |||||
comment: main key - desktop | |||||
joe-valid-ssh-key-notebook: | |||||
- user: joe | |||||
present: True | |||||
enc: ssh-rsa | |||||
comment: main key - notebook | |||||
joe-non-valid-ssh-key: | |||||
- user: joe | |||||
present: False | present: False | ||||
enc: ssh-rsa | enc: ssh-rsa | ||||
comment: obsolete key - removed | comment: obsolete key - removed | ||||
generate_dsa_keys: False | generate_dsa_keys: False | ||||
absent_dsa_keys: False | |||||
provide_dsa_keys: False | provide_dsa_keys: False | ||||
dsa: | dsa: | ||||
private_key: | | private_key: | | ||||
ssh-dss NOT_DEFINED | ssh-dss NOT_DEFINED | ||||
generate_ecdsa_keys: False | generate_ecdsa_keys: False | ||||
absent_ecdsa_keys: False | |||||
provide_ecdsa_keys: False | provide_ecdsa_keys: False | ||||
ecdsa: | ecdsa: | ||||
private_key: | | private_key: | | ||||
ecdsa-sha2-nistp256 NOT_DEFINED | ecdsa-sha2-nistp256 NOT_DEFINED | ||||
generate_rsa_keys: False | generate_rsa_keys: False | ||||
generate_rsa_size: 4096 | |||||
absent_rsa_keys: False | |||||
provide_rsa_keys: False | provide_rsa_keys: False | ||||
rsa: | rsa: | ||||
private_key: | | private_key: | | ||||
ssh-rsa NOT_DEFINED | ssh-rsa NOT_DEFINED | ||||
generate_ed25519_keys: False | generate_ed25519_keys: False | ||||
absent_ed25519_keys: False | |||||
provide_ed25519_keys: False | provide_ed25519_keys: False | ||||
ed25519: | ed25519: | ||||
private_key: | | private_key: | | ||||
-----END OPENSSH PRIVATE KEY----- | -----END OPENSSH PRIVATE KEY----- | ||||
public_key: | | public_key: | | ||||
ssh-ed25519 NOT_DEFINED | ssh-ed25519 NOT_DEFINED | ||||
known_hosts: | |||||
# The next 2 settings restrict the set of minions that will be added in | |||||
# the generated ssh_known_hosts files (the default is to match all minions) | |||||
target: '*' | |||||
expr_form: 'glob' | |||||
# Name of mining functions used to gather public keys and hostnames | |||||
# (the default values are shown here) | |||||
mine_keys_function: public_ssh_host_keys | |||||
mine_hostname_function: public_ssh_hostname | |||||
# List of DNS entries also pointing to our managed machines and that we want | |||||
# to inject in our generated ssh_known_hosts file | |||||
aliases: | |||||
- cname-to-minion.example.org | |||||
- alias.example.org | |||||
# specify DH parameters (see /etc/ssh/moduli) | |||||
moduli: | | |||||
# Time Type Tests Tries Size Generator Modulus | |||||
20120821045639 2 6 100 2047 2 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C604293680B09D63 | |||||
20120821045830 2 6 100 2047 2 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C6042936814C2FFB | |||||
20120821050046 2 6 100 2047 2 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C60429368214FC53 | |||||
20120821050054 2 6 100 2047 5 DD2047CBDBB6F8E919BC63DE885B34D0FD6E3DB2887D8B46FE249886ACED6B46DFCD5553168185FD376122171CD8927E60120FA8D01F01D03E58281FEA9A1ABE97631C828E41815F34FDCDF787419FE13A3137649AA93D2584230DF5F24B5C00C88B7D7DE4367693428C730376F218A53E853B0851BAB7C53C15DA7839CBE1285DB63F6FA45C1BB59FE1C5BB918F0F8459D7EF60ACFF5C0FA0F3FCAD1C5F4CE4416D4F4B36B05CDCEBE4FB879E95847EFBC6449CD190248843BC7EDB145FBFC4EDBB1A3C959298F08F3BA2CFBE231BBE204BE6F906209D28BD4820AB3E7BE96C26AE8A809ADD8D1A5A0B008E9570FA4C4697E116B8119892C60429368218E83F | |||||
# Required for openssh.known_hosts | |||||
mine_functions: | |||||
public_ssh_host_keys: | |||||
mine_function: cmd.run | |||||
cmd: cat /etc/ssh/ssh_host_*_key.pub | |||||
python_shell: True | |||||
public_ssh_hostname: | |||||
mine_function: grains.get | |||||
key: id |