Ejemplo n.º 1
0
    def install_agent(self, agent_wheel, vip_identity=None, publickey=None,
                      secretkey=None):

        if self.secure_agent_user:
            _log.info("Installing secure Volttron agent...")
        while True:
            agent_uuid = str(uuid.uuid4())
            if agent_uuid in self.agents:
                continue
            agent_path = os.path.join(self.install_dir, agent_uuid)
            try:
                os.mkdir(agent_path)
                break
            except OSError as exc:
                if exc.errno != errno.EEXIST:
                    raise
        try:
            if auth is not None and self.env.verify_agents:
                unpacker = auth.VolttronPackageWheelFile(agent_wheel,
                                                         certsobj=certs.Certs())
                unpacker.unpack(dest=agent_path)
            else:
                unpack(agent_wheel, dest=agent_path)

            # Is it ok to remove the wheel file after unpacking?
            os.remove(agent_wheel)

            final_identity = self._setup_agent_vip_id(
                agent_uuid, vip_identity=vip_identity)
            keystore = self.get_agent_keystore(agent_uuid, publickey, secretkey)

            self._authorize_agent_keys(agent_uuid, final_identity, keystore.public)

            if self.message_bus == 'rmq':
                rmq_user = get_fq_identity(final_identity,
                                           self.instance_name)
                certs.Certs().create_signed_cert_files(rmq_user, overwrite=False)

            if self.secure_agent_user:
                # When installing, we always create a new user, as anything
                # that already exists is untrustworthy
                created_user = self.add_agent_user(self.agent_name(agent_uuid),
                                                   agent_path)
                self.set_agent_user_permissions(created_user,
                                                agent_uuid,
                                                agent_path)
        except Exception:
            shutil.rmtree(agent_path)
            raise
        return agent_uuid
Ejemplo n.º 2
0
def _sign_agent_package(agent_package, **kwargs):
    """Sign an agent package"""
    if not os.path.exists(agent_package):
        raise AgentPackageError('Invalid package {}'.format(agent_package))

    cert_type = _cert_type_from_kwargs(**kwargs)
    files = _files_from_kwargs(**kwargs)
    certs_dir = kwargs.get('certs_dir', None)

    certsobj = None

    if certs_dir is not None:
        certsobj = certs.Certs(certs_dir)

    if cert_type == 'admin':
        if files:
            raise AgentPackageError("admin's aren't allowed to add files.")
        verified = auth.sign_as_admin(agent_package, 'admin', certsobj = certsobj)
    elif cert_type == 'creator':
        verified = auth.sign_as_creator(agent_package, 'creator', files, certsobj = certsobj)
    elif cert_type == 'initiator':
        verified = auth.sign_as_initiator(agent_package, 'initiator', files, certsobj = certsobj)
    elif cert_type == 'platform':
        verified = auth.sign_as_platform(agent_package, 'platform', files)
    else:
        raise AgentPackageError('Unknown packaging options')

    if verified:
        print('{} signed as {}'.format(agent_package, cert_type))
    else:
        print('Verification of signing failed!')
Ejemplo n.º 3
0
    def __init__(self):
        self.instance_name = get_platform_instance_name()
        # This is written durn the bootstrap phase of the rabbitmq installation
        # however for docker we don't write this at all so we need to
        # use the default location for this
        rmq_home_file = os.path.expanduser("~/.volttron_rmq_home")
        if os.path.isfile(rmq_home_file):
            with open(os.path.expanduser("~/.volttron_rmq_home")) as f:
                self.rabbitmq_server = f.read().strip()
        else:
            self.rabbitmq_server = os.path.expanduser(
                "~/rabbitmq_server/rabbitmq_server-3.7.7/")

        assert os.path.isdir(self.rabbitmq_server
                             ), "Missing rabbitmq server directory{}".format(
                                 self.rabbitmq_server)
        self.crts = certs.Certs()
        self.volttron_home = get_home()
        self.volttron_rmq_config = os.path.join(self.volttron_home,
                                                'rabbitmq_config.yml')
        self.default_pass = "******"
        self.config_opts = None
        try:
            self.load_rmq_config()
        except (IOError, yaml.YAMLError) as exc:
            self.config_opts = {}
        self._set_default_config()
Ejemplo n.º 4
0
def _create_certs(cfg_path, platform_cfg):
    print("Creating CA Certificate...")
    crts = certs.Certs()
    data = {
        "C": "US",
        "ST": "WA",
        "L": "Richmond",
        "O": "PNNL",
        "OU": "Volttron",
        "CN": f"{platform_cfg.get('instance-name')}-root-ca",
    }
    crts.create_root_ca(overwrite=False, **data)
    copy(crts.cert_file(crts.root_ca_name),
         crts.cert_file(crts.trusted_ca_name))

    print("Creating new web server certificate.")
    print(
        "Creating and signing new certificate using the newly created CA certificate."
    )
    name = f"{platform_cfg.get('instance-name')}-{PLATFORM_WEB}"
    crts.create_signed_cert_files(
        name=name + "-server",
        cert_type="server",
        ca_name=crts.root_ca_name,
        fqdn=get_hostname(),
    )

    master_web_cert = os.path.join(VOLTTRON_HOME, "certificates/certs/",
                                   name + "-server.crt")
    master_web_key = os.path.join(VOLTTRON_HOME, "certificates/private/",
                                  name + "-server.pem")
    print("Writing ssl cert and key paths to config.")
    with open(os.path.join(cfg_path), "a") as fout:
        fout.write(f"web-ssl-cert = {master_web_cert}\n")
        fout.write(f"web-ssl-key = {master_web_key}\n")
Ejemplo n.º 5
0
def _create_web_certs():
    global config_opts
    """
    Utility to create web server certificates
    Designed to be used in conjecture with get_cert_and_key
    As such, it assumes that the program has already checked
    for existing certs, and prompted the user to enter in 
    certificates that they have generated separately.
    """
    crts = certs.Certs()
    try:
        crts.ca_cert()
    except certs.CertError:
        print("WARNING! CA certificate does not exist.")
        prompt_str = "Create new root CA?"
        prompt = prompt_response(prompt_str, valid_answers=y_or_n, default='Y')
        if prompt in y:
            cert_data = {}
            print(
                "\nPlease enter the following details for web server certificate:"
            )
            prompt = '\tCountry:'
            cert_data['country'] = prompt_response(prompt, default='US')
            prompt = '\tState:'
            cert_data['state'] = prompt_response(prompt, mandatory=True)
            prompt = '\tLocation:'
            cert_data['location'] = prompt_response(prompt, mandatory=True)
            prompt = '\tOrganization:'
            cert_data['organization'] = prompt_response(prompt, mandatory=True)
            prompt = '\tOrganization Unit:'
            cert_data['organization-unit'] = prompt_response(prompt,
                                                             mandatory=True)
            cert_data['common-name'] = get_platform_instance_name(
            ) + '-root-ca'
            data = {
                'C': cert_data.get('country'),
                'ST': cert_data.get('state'),
                'L': cert_data.get('location'),
                'O': cert_data.get('organization'),
                'OU': cert_data.get('organization-unit'),
                'CN': cert_data.get('common-name')
            }
            crts.create_root_ca(overwrite=False, **data)
            copy(crts.cert_file(crts.root_ca_name),
                 crts.cert_file(crts.trusted_ca_name))
        else:
            return 1

    print("Creating new web server certificate.")
    crts.create_signed_cert_files(name=PLATFORM_WEB + "-server",
                                  cert_type='server',
                                  ca_name=crts.root_ca_name,
                                  fqdn=get_hostname())
    return 0
Ejemplo n.º 6
0
def _create_ca(override=True, data=None):
    """Creates a root ca cert using the Certs class"""
    crts = certs.Certs()
    if crts.ca_exists():
        if override:
            msg = '''Creating a new root ca will overwrite the current ca and
    invalidate any signed certs.
    
    Are you sure you want to do this? type 'yes' to continue: '''

        continue_yes = input(msg)
        if continue_yes.upper() != 'YES':
            return
    if not data:
        data = _create_cert_ui(crts.default_root_ca_cn)
    crts.create_root_ca(**data)
Ejemplo n.º 7
0
def _create_cert(name=None, **kwargs):
    """Create a cert using options specified on the command line"""

    crts = certs.Certs()
    if not crts.ca_exists():
        sys.stderr.write('Root CA must be created before certificates\n')
        sys.exit(0)

    cert_type = _cert_type_from_kwargs(**kwargs)

    if name == None:
        name = cert_type
        cert_data = _create_cert_ui(cert_type)
    else:
        cert_data = _create_cert_ui('{} ({})'.format(cert_type, name))

    crts.create_ca_signed_cert(name, **cert_data)
Ejemplo n.º 8
0
    def install_agent(self,
                      agent_wheel,
                      vip_identity=None,
                      publickey=None,
                      secretkey=None):
        while True:
            agent_uuid = str(uuid.uuid4())
            if agent_uuid in self.agents:
                continue
            agent_path = os.path.join(self.install_dir, agent_uuid)
            try:
                os.mkdir(agent_path)
                break
            except OSError as exc:
                if exc.errno != errno.EEXIST:
                    raise
        try:
            if auth is not None and self.env.verify_agents:
                unpacker = auth.VolttronPackageWheelFile(
                    agent_wheel, certsobj=certs.Certs())
                unpacker.unpack(dest=agent_path)
            else:
                unpack(agent_wheel, dest=agent_path)

            final_identity = self._setup_agent_vip_id(
                agent_uuid, vip_identity=vip_identity)
            if publickey is not None and secretkey is not None:
                keystore = self.get_agent_keystore(agent_uuid)
                keystore.public = publickey
                keystore.secret = secretkey

            self._authorize_agent_keys(agent_uuid, final_identity)

        except Exception:
            shutil.rmtree(agent_path)
            raise
        return agent_uuid
Ejemplo n.º 9
0
    def start_agent(self, agent_uuid):
        name = self.agent_name(agent_uuid)
        agent_dir = os.path.join(self.install_dir, agent_uuid)
        agent_path_with_name = os.path.join(agent_dir, name)
        execenv = self.agents.get(agent_uuid)
        if execenv and execenv.process.poll() is None:
            _log.warning('request to start already running agent %s',
                         agent_path_with_name)
            raise ValueError('agent is already running')

        pkg = UnpackedPackage(agent_path_with_name)
        if auth is not None and self.env.verify_agents:
            auth.UnpackedPackageVerifier(pkg.distinfo).verify()
        metadata = pkg.metadata
        try:
            exports = metadata['extensions']['python.exports']
        except KeyError:
            try:
                exports = metadata['exports']
            except KeyError:
                raise ValueError('no entry points exported')
        try:
            module = exports['volttron.agent']['launch']
        except KeyError:
            try:
                module = exports['setuptools.installation']['eggsecutable']
            except KeyError:
                _log.error('no agent launch class specified in package %s',
                           agent_path_with_name)
                raise ValueError('no agent launch class specified in package')
        config = os.path.join(pkg.distinfo, 'config')
        tag = self.agent_tag(agent_uuid)
        environ = os.environ.copy()
        environ['PYTHONPATH'] = ':'.join([agent_path_with_name] + sys.path)
        environ['PATH'] = (os.path.abspath(os.path.dirname(sys.executable)) +
                           ':' + environ['PATH'])
        if os.path.exists(config):
            environ['AGENT_CONFIG'] = config
        else:
            environ.pop('AGENT_CONFIG', None)
        if tag:
            environ['AGENT_TAG'] = tag
        else:
            environ.pop('AGENT_TAG', None)
        environ['AGENT_SUB_ADDR'] = self.subscribe_address
        environ['AGENT_PUB_ADDR'] = self.publish_address
        environ['AGENT_UUID'] = agent_uuid
        environ['_LAUNCHED_BY_PLATFORM'] = '1'

        # For backwards compatibility create the identity file if it does not
        # exist.
        identity_file = os.path.join(self.install_dir, agent_uuid, "IDENTITY")
        if not os.path.exists(identity_file):
            _log.debug(
                'IDENTITY FILE MISSING: CREATING IDENTITY FILE WITH VALUE: {}'.
                    format(agent_uuid))
            with open(identity_file, 'w') as fp:
                fp.write(agent_uuid)

        with open(identity_file, 'r') as fp:
            agent_vip_identity = fp.read()

        environ['AGENT_VIP_IDENTITY'] = agent_vip_identity

        module, _, func = module.partition(':')
        # if func:
        #     code = '__import__({0!r}, fromlist=[{1!r}]).{1}()'.format(module,
        #                                                               func)
        #     argv = [sys.executable, '-c', code]
        # else:
        argv = [sys.executable, '-m', module]
        resmon = getattr(self.env, 'resmon', None)
        agent_user = None

        data_dir = self._get_agent_data_dir(agent_path_with_name)

        if self.secure_agent_user:
            _log.info("Starting agent securely...")
            user_id_path = os.path.join(agent_dir, "USER_ID")
            try:
                with open(user_id_path, "r") as user_id_file:
                    volttron_agent_id = user_id_file.readline()
                    pwd.getpwnam(volttron_agent_id)
                    agent_user = volttron_agent_id
                    _log.info("Found secure volttron agent user {}".format(
                        agent_user))
            except (IOError, KeyError) as err:
                _log.info("No existing volttron agent user was found at {} due "
                          "to {}".format(user_id_path, err))

                # May be switched from normal to secure mode with existing agents. To handle this case
                # create users and also set permissions again for existing files
                agent_user = self.add_agent_user(name, agent_dir)
                self.set_agent_user_permissions(agent_user,
                                                agent_uuid,
                                                agent_dir)

                # additionally give permissions to contents of agent-data dir.
                # This is needed only for agents installed before switching to
                # secure mode. Agents installed in secure mode will own files
                # in agent-data dir
                # Moved this to the top so that "agent-data" directory gets
                # created in the beginning
                #data_dir = self._get_agent_data_dir(agent_path_with_name)

                for (root, directories, files) in os.walk(data_dir,
                                                          topdown=True):
                    for directory in directories:
                        self.set_acl_for_path("rwx", agent_user,
                                                  os.path.join(root, directory))
                    for f in files:
                        self.set_acl_for_path("rwx", agent_user,
                                              os.path.join(root, f))


        if self.message_bus == 'rmq':
            rmq_user = get_fq_identity(agent_vip_identity, self.instance_name)
            _log.info("Create RMQ user {} for agent {}".format(rmq_user, agent_vip_identity))

            self.rmq_mgmt.create_user_with_permissions(rmq_user, self.rmq_mgmt.get_default_permissions(rmq_user),
                                                       ssl_auth=True)
            key_file = certs.Certs().private_key_file(rmq_user)
            if not os.path.exists(key_file):
                # This could happen when user switches from zmq to rmq after installing agent
                _log.info(f"agent certs don't exists. creating certs for agent")
                certs.Certs().create_signed_cert_files(rmq_user, overwrite=False)

            if self.secure_agent_user:
                # give read access to user to its own private key file.
                self.set_acl_for_path("r", agent_user, key_file)

        if resmon is None:
            if agent_user:
                execenv = SecureExecutionEnvironment(agent_user=agent_user)
            else:
                execenv = ExecutionEnvironment()
        else:
            execreqs = self._read_execreqs(pkg.distinfo)
            execenv = self._reserve_resources(resmon, execreqs,
                                              agent_user=agent_user)
        execenv.name = name or agent_path_with_name
        _log.info('starting agent %s', agent_path_with_name)
        # data_dir = self._get_agent_data_dir(agent_path_with_name)
        _log.info("starting agent using {} ".format(type(execenv)))
        execenv.execute(argv, cwd=agent_path_with_name, env=environ, close_fds=True,
                        stdin=open(os.devnull), stdout=PIPE, stderr=PIPE)
        self.agents[agent_uuid] = execenv
        proc = execenv.process
        _log.info('agent %s has PID %s', agent_path_with_name, proc.pid)
        gevent.spawn(log_stream, 'agents.stderr', name, proc.pid, argv[0],
                      log_entries('agents.log', name, proc.pid, logging.ERROR,
                                  proc.stderr))
        gevent.spawn(log_stream, 'agents.stdout', name, proc.pid, argv[0],
                   ((logging.INFO, line) for line in (l.splitlines() for l
                      in proc.stdout)))

        return self.agent_status(agent_uuid)