replace predefined ssh keys with generated ones
This commit is contained in:
parent
8d3e913a8c
commit
28298d3ce6
3 changed files with 105 additions and 6 deletions
|
@ -33,14 +33,17 @@ else:
|
|||
backup_target = repo.get_node(node.metadata.get('backup-client/target'))
|
||||
|
||||
files['/etc/backup.priv'] = {
|
||||
'content': repo.vault.decrypt_file(join('backup', 'keys', f'{node.name}.key.vault')),
|
||||
'content': repo.libs.ssh.generate_ed25519_private_key(
|
||||
node.metadata.get('backup-client/user-name'),
|
||||
backup_target,
|
||||
),
|
||||
'mode': '0400',
|
||||
}
|
||||
|
||||
files['/usr/local/bin/generate-backup'] = {
|
||||
'content_type': 'mako',
|
||||
'context': {
|
||||
'username': node.metadata['backup-client']['user-name'],
|
||||
'username': node.metadata.get('backup-client/user-name'),
|
||||
'server': backup_target.metadata.get('backup-server/my_hostname'),
|
||||
'port': backup_target.metadata.get('backup-server/my_ssh_port'),
|
||||
'paths': backup_paths,
|
||||
|
|
|
@ -27,9 +27,6 @@ directories['/etc/backup-server/clients'] = {
|
|||
sudoers = {}
|
||||
|
||||
for nodename, config in node.metadata.get('backup-server/clients', {}).items():
|
||||
with open(join(repo.path, 'data', 'backup', 'keys', f'{nodename}.pub'), 'r') as f:
|
||||
pubkey = f.read().strip()
|
||||
|
||||
sudoers[config['user']] = nodename
|
||||
|
||||
users[config['user']] = {
|
||||
|
@ -41,7 +38,10 @@ for nodename, config in node.metadata.get('backup-server/clients', {}).items():
|
|||
}
|
||||
|
||||
files[f'/srv/backups/{nodename}/.ssh/authorized_keys'] = {
|
||||
'content': pubkey,
|
||||
'content': repo.libs.ssh.generate_ed25519_public_key(
|
||||
config['user'],
|
||||
node,
|
||||
),
|
||||
'owner': config['user'],
|
||||
'mode': '0400',
|
||||
'needs': {
|
||||
|
|
96
libs/ssh.py
Normal file
96
libs/ssh.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
from base64 import b64decode, b64encode
|
||||
from functools import lru_cache
|
||||
from hashlib import sha3_224
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import (
|
||||
Encoding,
|
||||
NoEncryption,
|
||||
PrivateFormat,
|
||||
PublicFormat,
|
||||
)
|
||||
|
||||
from bundlewrap.utils import Fault
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def generate_ed25519_private_key(username, node):
|
||||
return Fault(
|
||||
f'private key {username}@{node.name}',
|
||||
lambda username, node: _generate_ed25519_private_key(username, node),
|
||||
username=username,
|
||||
node=node,
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def generate_ed25519_public_key(username, node):
|
||||
return Fault(
|
||||
f'public key {username}@{node.name}',
|
||||
lambda username, node: _generate_ed25519_public_key(username, node),
|
||||
username=username,
|
||||
node=node,
|
||||
)
|
||||
|
||||
|
||||
def _generate_ed25519_private_key(username, node):
|
||||
privkey_bytes = Ed25519PrivateKey.from_private_bytes(_secret(username, node))
|
||||
|
||||
nondeterministic_privatekey = privkey_bytes.private_bytes(
|
||||
encoding=Encoding.PEM,
|
||||
format=PrivateFormat.OpenSSH,
|
||||
encryption_algorithm=NoEncryption(),
|
||||
).decode()
|
||||
|
||||
# get relevant lines from string
|
||||
nondeterministic_bytes = b64decode(
|
||||
''.join(nondeterministic_privatekey.split('\n')[1:-2])
|
||||
)
|
||||
|
||||
# sanity check
|
||||
if nondeterministic_bytes[98:102] != nondeterministic_bytes[102:106]:
|
||||
raise Exception("checksums should be the same: whats going on here?")
|
||||
|
||||
# replace random bytes with deterministic values
|
||||
random_bytes = sha3_224(_secret(username, node)).digest()[0:4]
|
||||
deterministic_bytes = (
|
||||
nondeterministic_bytes[:98]
|
||||
+ random_bytes
|
||||
+ random_bytes
|
||||
+ nondeterministic_bytes[106:]
|
||||
)
|
||||
|
||||
# reassemble file
|
||||
deterministic_privatekey = '\n'.join(
|
||||
[
|
||||
'-----BEGIN OPENSSH PRIVATE KEY-----',
|
||||
b64encode(deterministic_bytes).decode(),
|
||||
'-----END OPENSSH PRIVATE KEY-----',
|
||||
]
|
||||
) + '\n'
|
||||
|
||||
return deterministic_privatekey
|
||||
|
||||
|
||||
def _generate_ed25519_public_key(username, node):
|
||||
return (
|
||||
Ed25519PrivateKey.from_private_bytes(_secret(username, node))
|
||||
.public_key()
|
||||
.public_bytes(
|
||||
encoding=Encoding.OpenSSH,
|
||||
format=PublicFormat.OpenSSH,
|
||||
)
|
||||
.decode()
|
||||
+ f' {username}@{node.name}'
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _secret(username, node):
|
||||
return b64decode(
|
||||
str(
|
||||
node.repo.vault.random_bytes_as_base64_for(
|
||||
f"{username}@{node.name}", length=32
|
||||
)
|
||||
)
|
||||
)
|
Loading…
Reference in a new issue