Signed-off-by: René Jochum <rene@jochums.at>master
@@ -41,3 +41,47 @@ Installs the ssh daemon configuration file included in this formula | |||
by values from pillar. ``pillar.example`` results in the generation | |||
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. |
@@ -17,10 +17,24 @@ sshd_config: | |||
{% if salt['pillar.get']('openssh:generate_' ~ keyType ~ '_keys', False) %} | |||
ssh_generate_host_{{ keyType }}_key: | |||
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 | |||
{%- endif %} | |||
- creates: /etc/ssh/ssh_host_{{ keyType }}_key | |||
- 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) %} | |||
ssh_host_{{ keyType }}_key: | |||
file.managed: |
@@ -0,0 +1,8 @@ | |||
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 |
@@ -0,0 +1,38 @@ | |||
{# | |||
# 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 -%} |
@@ -139,7 +139,7 @@ | |||
# Restricting Users and Hosts | |||
# 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 | |||
# | |||
# Keep in mind that using AllowUsers or AllowGroups means that anyone | |||
@@ -156,6 +156,15 @@ | |||
# 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 #} | |||
{%- for keyword in sshd_config.keys() %} | |||
{#- Matches have to be at the bottem and should be handled differently -#} |
@@ -0,0 +1,16 @@ | |||
{% 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 |
@@ -1,45 +1,56 @@ | |||
{% 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': { | |||
'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': { | |||
'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': { | |||
'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 | |||
) | |||
%} | |||
@@ -0,0 +1,8 @@ | |||
{% 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 %} |
@@ -22,7 +22,7 @@ sshd_config: | |||
HostbasedAuthentication: 'no' | |||
PermitEmptyPasswords: 'no' | |||
ChallengeResponseAuthentication: 'no' | |||
AuthenticationMethods 'publickey,keyboard-interactive' | |||
AuthenticationMethods: 'publickey,keyboard-interactive' | |||
X11Forwarding: 'yes' | |||
X11DisplayOffset: 10 | |||
PrintMotd: 'no' | |||
@@ -36,7 +36,6 @@ sshd_config: | |||
DenyUsers: 'yoda chewbaca@112.10.21.1' | |||
AllowGroups: 'wheel staff imperial' | |||
DenyGroups: 'rebel' | |||
Deny | |||
matches: | |||
sftp_chroot: | |||
type: | |||
@@ -46,20 +45,31 @@ sshd_config: | |||
X11Forwarding: no | |||
AllowTcpForwarding: no | |||
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: | |||
auth: | |||
joe: | |||
- name: JOE_VALID_SSH_PUBLIC_KEY | |||
joe-valid-ssh-key-desktop: | |||
- user: joe | |||
present: True | |||
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 | |||
enc: ssh-rsa | |||
comment: obsolete key - removed | |||
generate_dsa_keys: False | |||
absent_dsa_keys: False | |||
provide_dsa_keys: False | |||
dsa: | |||
private_key: | | |||
@@ -70,6 +80,7 @@ openssh: | |||
ssh-dss NOT_DEFINED | |||
generate_ecdsa_keys: False | |||
absent_ecdsa_keys: False | |||
provide_ecdsa_keys: False | |||
ecdsa: | |||
private_key: | | |||
@@ -80,6 +91,8 @@ openssh: | |||
ecdsa-sha2-nistp256 NOT_DEFINED | |||
generate_rsa_keys: False | |||
generate_rsa_size: 4096 | |||
absent_rsa_keys: False | |||
provide_rsa_keys: False | |||
rsa: | |||
private_key: | | |||
@@ -90,6 +103,7 @@ openssh: | |||
ssh-rsa NOT_DEFINED | |||
generate_ed25519_keys: False | |||
absent_ed25519_keys: False | |||
provide_ed25519_keys: False | |||
ed25519: | |||
private_key: | | |||
@@ -98,3 +112,36 @@ openssh: | |||
-----END OPENSSH PRIVATE KEY----- | |||
public_key: | | |||
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 |