Beispiel #1
0
def fetch_device_metadata(dev, logger=logger):

    with Locker('dev.metadata'):
        setup_endpoints(dev)
        logger.info('Fetching node metadata...')
        can_read_cert()

        dev_md_req = mtls_request('get',
                                  'device-metadata',
                                  dev=dev,
                                  requester_name="Fetching node metadata")
        if dev_md_req is None or not dev_md_req.ok:
            logger.error('Fetching failed.')
            return

        metadata = dev_md_req.json()

        logger.info('metadata retrieved.')

        if os.path.exists(SECRET_DEV_METADATA_PATH
                          ) and not os.path.isfile(SECRET_DEV_METADATA_PATH):
            logger.error(
                "Error: The filesystem object '{}' is not a file. Looks like a break-in attempt."
                .format(SECRET_DEV_METADATA_PATH))
            exit(1)

        with open(SECRET_DEV_METADATA_PATH, "w") as outfile:
            json.dump(metadata, outfile, indent=4)
        os.chmod(SECRET_DEV_METADATA_PATH, 0o600)
        logger.info('metadata stored.')
Beispiel #2
0
def run(ping=True, dev=False, logger=logger):

    with Locker('ping'):
        setup_endpoints(dev)
        bootstrapping = is_bootstrapping()

        if bootstrapping:
            device_id = generate_device_id()
            logger.info('Got WoTT ID: {}'.format(device_id))
            write_metadata({'device_id': device_id}, rewrite_file=True)
        else:
            device_id = get_device_id()
            try_enroll_in_operation_mode(device_id=device_id, dev=dev)
            write_metadata({'device_id': device_id}, rewrite_file=False)
            if not time_for_certificate_renewal(
            ) and not is_certificate_expired():
                if ping:
                    send_ping(dev=dev)
                    time_to_cert_expires = get_certificate_expiration_date(
                    ) - datetime.datetime.now(datetime.timezone.utc)
                    logger.info(
                        "Certificate expires in {} days and {} hours. No need for renewal."
                        "Renewal threshold is set to {} days.".format(
                            time_to_cert_expires.days,
                            floor(time_to_cert_expires.seconds / 60 / 60),
                            RENEWAL_THRESHOLD,
                        ))
                    exit(0)
                else:
                    return
            logger.info('My WoTT ID is: {}'.format(device_id))

        logger.info('Generating certificate...')
        gen_key = generate_cert(device_id)

        ca = get_ca_cert()
        if not ca:
            logger.error('Unable to retrieve CA cert. Exiting.')
            exit(1)

        logger.info('Submitting CSR...')

        enroll_token = None
        if bootstrapping:
            crt = sign_cert(gen_key['csr'], device_id)
            enroll_token = get_enroll_token()
            if enroll_token is not None:
                logger.info('Node enrollment token found...')
        elif is_certificate_expired():
            crt = renew_expired_cert(gen_key['csr'], device_id)
        else:
            crt = renew_cert(gen_key['csr'], device_id)

        if not crt:
            logger.error('Unable to sign CSR. Exiting.')
            exit(1)

        if enroll_token is None:
            logger.info('Got Claim Token: {}'.format(crt['claim_token']))
            logger.info(
                'Claim your node: {WOTT_ENDPOINT}/claim-device?device_id={device_id}&claim_token={claim_token}'
                .format(WOTT_ENDPOINT=DASH_ENDPOINT,
                        device_id=device_id,
                        claim_token=crt['claim_token']))

        logger.info('Writing certificate and key to disk...')
        with open(CLIENT_CERT_PATH, 'w') as f:
            f.write(crt['crt'])
        os.chmod(CLIENT_CERT_PATH, 0o644)

        with open(CA_CERT_PATH, 'w') as f:
            f.write(ca)
        os.chmod(CA_CERT_PATH, 0o644)

        with open(CLIENT_KEY_PATH, 'w') as f:
            f.write(gen_key['key'])
        os.chmod(CLIENT_KEY_PATH, 0o600)

        with open(COMBINED_PEM_PATH, 'w') as f:
            f.write(gen_key['key'])
            f.write(crt['crt'])
        os.chmod(COMBINED_PEM_PATH, 0o600)

        send_ping(dev=dev)

        if enroll_token is not None:
            logger.info('Enroll node by token...')
            if enroll_device(enroll_token, crt['claim_token'], device_id):
                enroll_token = None

        logger.info("Writing config...")
        config = configparser.ConfigParser()
        config['DEFAULT'] = {'fallback_token': crt['fallback_token']}
        if enroll_token is not None:
            config['DEFAULT'][
                'enroll_token'] = enroll_token  # if enroll fails, store enroll token for next run
        with open(INI_PATH, 'w') as configfile:
            config.write(configfile)
        os.chmod(INI_PATH, 0o600)
Beispiel #3
0
def fetch_credentials(dev, logger=logger):
    def clear_credentials(path):
        files = glob.glob(os.path.join(path, '**/*.json'), recursive=True)
        for file in files:
            os.remove(os.path.join(path, file))
            logger.debug("remove...{}".format(file))

    with Locker('credentials'):
        setup_endpoints(dev)
        logger.info('Fetching credentials...')
        can_read_cert()

        credentials_req = mtls_request('get',
                                       'credentials',
                                       dev=dev,
                                       requester_name="Fetch credentials")
        if credentials_req is None or not credentials_req.ok:
            logger.error('Fetching failed.')
            return
        credentials = credentials_req.json()

        logger.info('Credentials retrieved.')

        if not os.path.exists(CREDENTIALS_PATH):
            os.mkdir(CREDENTIALS_PATH, 0o711)
        else:
            os.chmod(CREDENTIALS_PATH, 0o711)

        if not os.path.isdir(CREDENTIALS_PATH):
            logger.error(
                "There is file named as our credentials dir(%s), that's strange...",
                CREDENTIALS_PATH)
            exit(1)

        clear_credentials(CREDENTIALS_PATH)

        # group received credentials, by linux_user, name
        credentials_grouped = {}
        for cred in credentials:
            name = cred['name']
            owner = cred['linux_user'] if 'linux_user' in cred else ''
            if owner not in credentials_grouped:
                credentials_grouped[owner] = {}
            if name not in credentials_grouped[owner]:
                credentials_grouped[owner][name] = cred['data']
            else:
                logger.error(
                    "Duplicated owner/name combination for credentials ({}/{}). Skipped."
                    .format(owner, name))

        root_pw = pwd.getpwnam("root")

        for owner in credentials_grouped:

            pw = root_pw  # if no owner, use 'root'
            if owner:
                try:
                    pw = pwd.getpwnam(owner)
                except KeyError:
                    logger.warning(
                        "There are credentials with wrong owner ({}). Skipped."
                        .format(owner))
                    continue

            uid = pw.pw_uid
            gid = pw.pw_gid

            owner_path = CREDENTIALS_PATH if not owner else os.path.join(
                CREDENTIALS_PATH, owner)

            if owner and not os.path.isdir(owner_path):
                if os.path.exists(owner_path):
                    logger.error(
                        "There is a file with name of system user in credentials directory ({})."
                        .format(owner_path))
                    exit(1)
                os.mkdir(owner_path, 0o700)
            os.chown(
                owner_path, uid,
                gid)  # update ownership if user existence in system changed

            for name in credentials_grouped[owner]:
                credential_file_path = os.path.join(owner_path,
                                                    "{}.json".format(name))
                file_credentials = credentials_grouped[owner][name]

                logger.debug(
                    'Store credentials to {}'.format(credential_file_path))

                with open(credential_file_path, 'w') as outfile:
                    json.dump(file_credentials, outfile, indent=4)

                os.chmod(credential_file_path, 0o400)
                os.chown(credential_file_path, uid, gid)
Beispiel #4
0
CONFIG_PATH = os.getenv('CONFIG_PATH', '/opt/wott')
if CONFINEMENT == Confinement.SNAP:
    Locker.LOCKDIR = CONFIG_PATH
CERT_PATH = os.getenv('CERT_PATH', os.path.join(CONFIG_PATH, 'certs'))
CREDENTIALS_PATH = os.getenv('CREDENTIALS_PATH',
                             os.path.join(CONFIG_PATH, 'credentials'))
BACKUPS_PATH = os.path.join(CONFIG_PATH, 'backups')

CLIENT_CERT_PATH = os.path.join(CERT_PATH, 'client.crt')
CLIENT_KEY_PATH = os.path.join(CERT_PATH, 'client.key')
CA_CERT_PATH = os.path.join(CERT_PATH, 'ca.crt')
COMBINED_PEM_PATH = os.path.join(CERT_PATH, 'combined.pem')
INI_PATH = os.path.join(CONFIG_PATH, 'config.ini')
SECRET_DEV_METADATA_PATH = os.path.join(CONFIG_PATH, 'device_metadata.json')

with Locker('config'):
    if not os.path.isdir(CONFIG_PATH):
        os.makedirs(CONFIG_PATH)
        os.chmod(CONFIG_PATH, 0o711)
    if not os.path.isdir(BACKUPS_PATH):
        os.makedirs(BACKUPS_PATH, 0o711)

# This needs to be adjusted once we have
# changed the certificate life span from 7 days.
RENEWAL_THRESHOLD = 3

logger = logging.getLogger('agent')


def is_bootstrapping():
    # Create path if it doesn't exist