Compare commits

..

No commits in common. "8532f914c36ea31ea20b7efe23ece6a520560036" and "8a9434a384fa00e4af03d0d8a34765649c7607c6" have entirely different histories.

4 changed files with 82 additions and 102 deletions

View file

@ -1,4 +1,5 @@
Host * Host *
#UserKnownHostsFile ~/.ssh/known_hosts ~/.ssh/known_hosts.d/%k
SendEnv LANG LC_* SendEnv LANG LC_*
HashKnownHosts yes HashKnownHosts yes
GSSAPIAuthentication yes GSSAPIAuthentication yes

View file

@ -1,72 +1,65 @@
# on debian bullseye raspberry images, starting the systemd ssh if not node.metadata.get('FIXME_dont_touch_sshd', False):
# daemon seems to collide with an existing sysv daemon # on debian bullseye raspberry images, starting the systemd ssh
dont_touch_sshd = node.metadata.get('FIXME_dont_touch_sshd', False), # daemon seems to collide with an existing sysv daemon
directories = {
directories = { '/etc/ssh': {
'/etc/ssh': { 'purge': True,
'purge': True, 'mode': '0755',
'mode': '0755', }
'skip': dont_touch_sshd,
} }
}
files = { files = {
'/etc/ssh/moduli': { '/etc/ssh/moduli': {
'content_type': 'any', 'content_type': 'any',
'skip': dont_touch_sshd,
},
'/etc/ssh/ssh_config': {
'triggers': [
'svc_systemd:ssh:restart'
],
'skip': dont_touch_sshd,
},
'/etc/ssh/ssh_config': {
'content_type': 'mako',
'context': {
}, },
'triggers': [ '/etc/ssh/ssh_config': {
'svc_systemd:ssh:restart' 'triggers': [
], 'svc_systemd:ssh:restart'
'skip': dont_touch_sshd, ],
},
'/etc/ssh/sshd_config': {
'content_type': 'mako',
'context': {
'users': sorted(node.metadata.get('ssh/allow_users')),
}, },
'triggers': [ '/etc/ssh/ssh_config': {
'svc_systemd:ssh:restart' 'content_type': 'mako',
], 'context': {
'skip': dont_touch_sshd, },
}, 'triggers': [
'/etc/ssh/ssh_host_ed25519_key': { 'svc_systemd:ssh:restart'
'content': node.metadata.get('ssh/host_key/private') + '\n', ],
'mode': '0600', },
'triggers': [ '/etc/ssh/sshd_config': {
'svc_systemd:ssh:restart' 'content_type': 'mako',
], 'context': {
}, 'users': sorted(node.metadata.get('ssh/allow_users')),
'/etc/ssh/ssh_host_ed25519_key.pub': { },
'content': node.metadata.get('ssh/host_key/public') + '\n', 'triggers': [
'mode': '0644', 'svc_systemd:ssh:restart'
'triggers': [ ],
'svc_systemd:ssh:restart' },
], '/etc/ssh/ssh_host_ed25519_key': {
}, 'content': node.metadata.get('ssh/host_key/private') + '\n',
'/etc/ssh/ssh_known_hosts': { 'mode': '0600',
'content': '\n'.join( 'triggers': [
repo.libs.ssh.known_hosts_entry_for(other_node) 'svc_systemd:ssh:restart'
for other_node in sorted(repo.nodes) ],
if other_node != node },
and other_node.has_bundle('ssh') '/etc/ssh/ssh_host_ed25519_key.pub': {
) + '\n', 'content': node.metadata.get('ssh/host_key/public') + '\n',
}, 'mode': '0644',
} 'triggers': [
'svc_systemd:ssh:restart'
],
},
'/etc/ssh/ssh_known_hosts': {
'content': '\n'.join(
repo.libs.ssh.known_hosts_entry_for(other_node)
for other_node in sorted(repo.nodes)
if other_node != node
and other_node.has_bundle('ssh')
) + '\n',
},
}
svc_systemd['ssh'] = { svc_systemd['ssh'] = {
'needs': [ 'needs': [
'tag:ssh_users', 'tag:ssh_users',
], ],
'skip': dont_touch_sshd, }
}

View file

@ -1,4 +1,3 @@
from ipaddress import ip_interface
from base64 import b64decode from base64 import b64decode
@ -33,34 +32,3 @@ def host_key(metadata):
} }
}, },
} }
@metadata_reactor.provides(
'ssh/hostnames',
)
def hostnames(metadata):
ips = set()
for network in node.metadata.get('network').values():
if network.get('ipv4', None):
ips.add(str(ip_interface(network['ipv4']).ip))
if network.get('ipv6', None):
ips.add(str(ip_interface(network['ipv6']).ip))
domains = {
domain
for domain, records in node.metadata.get('dns').items()
for type, values in records.items()
if type in {'A', 'AAAA'}
and set(values) & ips
}
return {
'ssh': {
'hostnames': {
node.hostname,
*ips,
*domains,
}
},
}

View file

@ -2,6 +2,7 @@ from base64 import b64decode, b64encode
from hashlib import sha3_224, sha1 from hashlib import sha3_224, sha1
from functools import cache from functools import cache
import hmac import hmac
from ipaddress import ip_interface
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, PublicFormat, NoEncryption from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, PublicFormat, NoEncryption
@ -56,13 +57,30 @@ def generate_ed25519_key_pair(secret):
# - `bw debug -c 'repo.libs.ssh.known_hosts_entry_for(repo.get_node(<node with hostname 10.0.0.5>), <salt from ssh-keygen>)'` # - `bw debug -c 'repo.libs.ssh.known_hosts_entry_for(repo.get_node(<node with hostname 10.0.0.5>), <salt from ssh-keygen>)'`
@cache @cache
def known_hosts_entry_for(node, test_salt=None): def known_hosts_entry_for(node, test_salt=None):
ips = set()
for network in node.metadata.get('network').values():
if network.get('ipv4', None):
ips.add(str(ip_interface(network['ipv4']).ip))
if network.get('ipv6', None):
ips.add(str(ip_interface(network['ipv6']).ip))
domains = {
domain
for domain, records in node.metadata.get('dns').items()
for type, values in records.items()
if type in {'A', 'AAAA'}
and set(values) & ips
}
lines = set() lines = set()
for hostname in sorted(node.metadata.get('ssh/hostnames')): for hostname in {node.hostname, *ips, *domains}:
if test_salt: if test_salt:
salt = b64decode(test_salt) salt = b64decode(test_salt)
else: else:
salt = sha1((node.metadata.get('id') + hostname).encode()).digest() salt = sha1(node.metadata.get('id').encode()).digest()
hash = hmac.new(salt, hostname.encode(), sha1).digest() hash = hmac.new(salt, hostname.encode(), sha1).digest()
pubkey = node.metadata.get('ssh/host_key/public') pubkey = node.metadata.get('ssh/host_key/public')