is_known_as known_hosts metadata
This commit is contained in:
		
							parent
							
								
									637ab05590
								
							
						
					
					
						commit
						fe884f446a
					
				
					 4 changed files with 30 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -66,12 +66,13 @@ files = {
 | 
			
		|||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    '/etc/ssh/ssh_known_hosts': {
 | 
			
		||||
        'content': '\n'.join(
 | 
			
		||||
            repo.libs.ssh.known_hosts_entry_for(other_node)
 | 
			
		||||
                for other_node in sorted(repo.nodes)
 | 
			
		||||
        'content': '\n'.join(sorted(
 | 
			
		||||
            line
 | 
			
		||||
                for other_node in repo.nodes
 | 
			
		||||
                if other_node != node
 | 
			
		||||
                and other_node.has_bundle('ssh')
 | 
			
		||||
        ) + '\n',
 | 
			
		||||
                for line in other_node.metadata.get('ssh/is_known_as')
 | 
			
		||||
        )) + '\n',
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ from base64 import b64decode
 | 
			
		|||
defaults = {
 | 
			
		||||
    'ssh': {
 | 
			
		||||
        'multiplex_incoming': True,
 | 
			
		||||
        'is_known_as': set(), # known_hosts for other nodes
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +48,7 @@ def host_key(metadata):
 | 
			
		|||
def hostnames(metadata):
 | 
			
		||||
    ips = set()
 | 
			
		||||
 | 
			
		||||
    for network in node.metadata.get('network').values():
 | 
			
		||||
    for network in metadata.get('network').values():
 | 
			
		||||
        if network.get('ipv4', None):
 | 
			
		||||
            ips.add(str(ip_interface(network['ipv4']).ip))
 | 
			
		||||
        if network.get('ipv6', None):
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +56,7 @@ def hostnames(metadata):
 | 
			
		|||
 | 
			
		||||
    domains = {
 | 
			
		||||
        domain
 | 
			
		||||
            for domain, records in node.metadata.get('dns').items()
 | 
			
		||||
            for domain, records in metadata.get('dns').items()
 | 
			
		||||
            for type, values in records.items()
 | 
			
		||||
            if type in {'A', 'AAAA'}
 | 
			
		||||
            and set(values) & ips
 | 
			
		||||
| 
						 | 
				
			
			@ -70,3 +71,18 @@ def hostnames(metadata):
 | 
			
		|||
            }
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@metadata_reactor.provides(
 | 
			
		||||
    'ssh/is_known_as',
 | 
			
		||||
)
 | 
			
		||||
def is_known_as(metadata):
 | 
			
		||||
    return {
 | 
			
		||||
        'ssh': {
 | 
			
		||||
            'is_known_as': repo.libs.ssh.known_hosts_entry_for(
 | 
			
		||||
                node_id=metadata.get('id'),
 | 
			
		||||
                hostnames=tuple(sorted(metadata.get('ssh/hostnames'))),
 | 
			
		||||
                pubkey=metadata.get('ssh/host_key/public'),
 | 
			
		||||
            ),
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,9 @@ from os.path import expanduser
 | 
			
		|||
def apply_start(repo, target, nodes, interactive=False, **kwargs):
 | 
			
		||||
    with open(expanduser('~/.ssh/known_hosts_ckn'), 'w+') as file:
 | 
			
		||||
        file.write('\n'.join(sorted(
 | 
			
		||||
            repo.libs.ssh.known_hosts_entry_for(node)
 | 
			
		||||
            line
 | 
			
		||||
                for node in repo.nodes
 | 
			
		||||
                if node.has_bundle('ssh')
 | 
			
		||||
                for line in node.metadata.get('ssh/is_known_as')
 | 
			
		||||
 | 
			
		||||
        )))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,18 +55,17 @@ def generate_ed25519_key_pair(secret):
 | 
			
		|||
# - take the salt from the ssh-ed25519 entry (first field after '|1|')
 | 
			
		||||
# - `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
 | 
			
		||||
def known_hosts_entry_for(node, test_salt=None):
 | 
			
		||||
def known_hosts_entry_for(node_id, hostnames, pubkey, test_salt=None):
 | 
			
		||||
    lines = set()
 | 
			
		||||
 | 
			
		||||
    for hostname in sorted(node.metadata.get('ssh/hostnames')):
 | 
			
		||||
    for hostname in hostnames:
 | 
			
		||||
        if test_salt:
 | 
			
		||||
            salt = b64decode(test_salt)
 | 
			
		||||
        else:
 | 
			
		||||
            salt = sha1((node.metadata.get('id') + hostname).encode()).digest()
 | 
			
		||||
            salt = sha1((node_id + hostname).encode()).digest()
 | 
			
		||||
 | 
			
		||||
        hash = hmac.new(salt, hostname.encode(), sha1).digest()
 | 
			
		||||
        pubkey = node.metadata.get('ssh/host_key/public')
 | 
			
		||||
 | 
			
		||||
        lines.add(f'|1|{b64encode(salt).decode()}|{b64encode(hash).decode()} {" ".join(pubkey.split()[:2])}')
 | 
			
		||||
 | 
			
		||||
    return '\n'.join(sorted(lines))
 | 
			
		||||
    return lines
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue