def add_repo(distribution, components=['main'], site='http://httpredir.debian.org/debian', src=False, arch=[], name=None): comps = ' '.join(components) options = '' if arch: options = ' [ arch={} ]'.format(','.join(arch)) line = '{}{} {} {} {}\n'.format('deb-src' if src else 'deb', options, site, distribution, comps, ) if name is None: name = '{}_{}{}'.format(distribution, '_'.join(components), '' if not src else '-sources') path = remote.path.join(config['apt_sources_list_d'], name + '.list') upload = fs.upload_string(line, path, create_parent=True) if upload.changed: info_update_timestamp().mark_stale() return Changed(msg='Added apt repository: {}'.format(line)) return Unchanged(msg='Already present: {}'.format(line))
def add_repo(distribution, components=['main'], site='http://deb.debian.org/debian', src=False, arch=[], name=None): comps = ' '.join(components) options = '' if arch: options = ' [ arch={} ]'.format(','.join(arch)) line = '{}{} {} {} {}\n'.format( 'deb-src' if src else 'deb', options, site, distribution, comps, ) if name is None: name = '{}_{}{}'.format(distribution, '_'.join(components), '' if not src else '-sources') path = remote.path.join(config['apt_sources_list_d'], name + '.list') upload = fs.upload_string(line, path, create_parent=True) if upload.changed: info_update_timestamp().mark_stale() return Changed(msg='Added apt repository: {}'.format(line)) return Unchanged(msg='Already present: {}'.format(line))
def run(): # create source.list.d fs.create_dir('/etc/apt/sources.list.d') if info['lsb.dist_id'] == 'Ubuntu': fs.upload_string(tpl.render(), '/etc/apt/sources.list.d/ubuntu-mirrors.list') elif info['lsb.dist_id'] == 'Debian': raise NotImplementedError else: raise NotImplementedError # FIXME: do not do this for raspbian, needs os-release check fs.remove_file('/etc/apt/sources.list') apt.update(max_age=60) apt.update(max_age=60) apt.update(max_age=60)
def ensure_certificate(hostname): cert_rpath = remote.path.join(config['sslcert_cert_dir'], hostname + '.crt') chain_rpath = remote.path.join(config['sslcert_cert_dir'], hostname + '.chain.crt') key_rpath = remote.path.join(config['sslcert_key_dir'], hostname + '.pem') # first, ensure any certificate exists on the host. otherwise, # webservers like nginx will likely not start if not (remote.lstat(cert_rpath) and remote.lstat(key_rpath) and remote.lstat(chain_rpath)): log.debug('Remote certificate {}, key {}, chain {} not found'.format( cert_rpath, key_rpath, chain_rpath)) key, cert = generate_self_signed_cert(hostname) # FIXME: maybe use install cert here. fs.upload_string(key, key_rpath) fs.upload_string(cert, cert_rpath) fs.upload_string(cert, chain_rpath) return Changed( msg='No certificate {} / key {} / chain {} found. A self-signed ' 'certficate from a reputable snake-oil vendor was installed.'. format(cert_rpath, key_rpath, chain_rpath)) return Unchanged( 'Certificate for hostname {} already preset'.format(hostname))
def install_unit_string(unit_name, buf, reload=True): _, ext = os.path.splitext(unit_name) if ext not in UNIT_EXTS: raise ValueError('unit_name should be one of {}'.format(UNIT_EXTS)) remote_unit = os.path.join(config['systemd_unit_dir'], os.path.basename(unit_name)) if fs.upload_string(buf, remote_unit).changed: if reload: daemon_reload() return Changed(msg='Installed {}'.format(remote_unit)) return Unchanged(msg='{} already installed'.format(remote_unit))
def install_strict_ssh(allow_users=['root'], allow_groups=None, address_family="any", permit_root=True, modern_ciphers=True, sftp_enabled=True, agent_forwarding=False, x11=False, tcp_forwarding=True, unix_forwarding=True, tunnel=False, port=22, use_dns=False, print_motd=False, auto_restart=True, check_sshd_config=True, password_enabled=None): # FIXME: change default in jinja templates to strict reporting of missing # values to avoid creating broken ssh configs # FIXME: add (possibly generic) support for atomic-tested-configuration # swaps (i.e. run sshd -t on a config) tpl = ssh_preset.templates.render( 'sshd_config', allow_users=allow_users, allow_groups=allow_groups, address_family=address_family, permit_root=permit_root, modern_ciphers=modern_ciphers, sftp_enabled=sftp_enabled, agent_forwarding=agent_forwarding, x11=x11, tcp_forwarding=tcp_forwarding, unix_forwarding=unix_forwarding, tunnel=tunnel, ports=port if isinstance(port, list) else [port], print_motd=print_motd, password_enabled=password_enabled) if fs.upload_string(tpl, '/etc/ssh/sshd_config').changed: if check_sshd_config: proc.run(['sshd', '-t']) # FIXME: we may want to abstract the init-system here if auto_restart: systemd.restart_unit('ssh.service') return Changed(msg='Changed sshd configuration') return Unchanged(msg='sshd config already strict')
def setup_rsyslog(server_addr): # setup papertrail # FIXME: this is part of remand now changed = False changed = apt.install_packages(['rsyslog-gnutls']).changed changed |= fs.upload_file(papertrail.files['papertrail-bundle.pem'], '/etc/papertrail-bundle.pem').changed changed |= fs.upload_string( papertrail.templates.render('papertrail.conf', addr=server_addr), '/etc/rsyslog.d/papertrail.conf', ).changed if changed: systemd.restart_unit('rsyslog.service') return Changed( msg='Setup papertrail logging to {}'.format(server_addr)) return Unchanged(msg='Papertrail already setup to {}'.format(server_addr))
def install_strict_ssh(allow_users=['root'], allow_groups=None, address_family="any", permit_root=True, modern_ciphers=True, sftp_enabled=True, agent_forwarding=False, x11=False, tcp_forwarding=True, unix_forwarding=True, tunnel=False, port=22, use_dns=False, print_motd=False, auto_restart=True, check_sshd_config=True): # FIXME: change default in jinja templates to strict reporting of missing # values to avoid creating broken ssh configs # FIXME: add (possibly generic) support for atomic-tested-configuration # swaps (i.e. run sshd -t on a config) tpl = ssh_preset.templates.render('sshd_config', allow_users=allow_users, allow_groups=allow_groups, address_family=address_family, permit_root=permit_root, modern_ciphers=modern_ciphers, sftp_enabled=sftp_enabled, agent_forwarding=agent_forwarding, x11=x11, tcp_forwarding=tcp_forwarding, unix_forwarding=unix_forwarding, tunnel=tunnel, port=port, print_motd=print_motd) if fs.upload_string(tpl, '/etc/ssh/sshd_config').changed: if check_sshd_config: proc.run(['sshd', '-t']) # FIXME: we may want to abstract the init-system here if auto_restart: systemd.restart_unit('ssh.service') return Changed(msg='Changed sshd configuration') return Unchanged(msg='sshd config already strict')
def set_authorized_keys(files, user='******', fix_permissions=True): ak_file = init_authorized_keys(user, fix_permissions).value kf = KeyFile() for fn in files: kf.add_from_file(fn) # directory is guaranteed to exist now, with correct permissions upload = fs.upload_string(str(kf), ak_file) if upload.changed and fix_permissions: fs.chmod(ak_file, AK_FILE_PERMS) fps = ', '.join(k.readable_fingerprint for k in kf.keys) if upload.changed: return Changed( msg='SSH authorized keys for {} set to: {}'.format(user, fps)) return Unchanged( msg='SSH authorized keys for {} unchanged ({})'.format(user, fps))
def set_hostname(hostname, domain=None, config_only=False): prev_hostname = info_hostname() changed = False changed |= fs.upload_string('{}\n'.format(hostname), '/etc/hostname').changed if not config_only and prev_hostname != hostname: proc.run(['hostname', hostname]) changed = True # update /etc/hosts # this will also set the domain name # see http://jblevins.org/log/hostname # # we adopt the following convention: host_line = '127.0.1.1\t' + hostname if domain: host_line = '127.0.1.1\t{}.{}\t{}'.format(hostname, domain, hostname) with fs.edit('/etc/hosts') as hosts: if host_line not in hosts.lines(): hosts.comment_out(r'^127.0.1.1') # comment out old lines lines = [host_line] + hosts.lines() hosts.set_lines(lines) changed |= hosts.changed if changed: info_hostname.invalidate_cache() info_fqdn.invalidate_cache() return Changed(msg='Hostname changed from {} to {}'.format( prev_hostname, hostname)) return Unchanged(msg='Hostname already set to {}'.format(hostname))
def set_authorized_keys(files, user='******', fix_permissions=True): ak_file = init_authorized_keys(user, fix_permissions).value kf = KeyFile() for fn in files: kf.add_from_file(fn) # directory is guaranteed to exist now, with correct permissions upload = fs.upload_string(str(kf), ak_file) if upload.changed and fix_permissions: fs.chmod(ak_file, AK_FILE_PERMS) fs.chown(ak_file, uid=user) fps = ', '.join(k.readable_fingerprint for k in kf.keys) if upload.changed: return Changed( msg='SSH authorized keys for {} set to: {}'.format(user, fps)) return Unchanged( msg='SSH authorized keys for {} unchanged ({})'.format(user, fps))