Exemple #1
0
    def _GenerateSshKey(self, key_type, key_dest):
        """Generate a new SSH key.

    Args:
      key_type: string, the type of the SSH key.
      key_dest: string, a file location to store the SSH key.
    """
        # Create a temporary file to save the created RSA keys.
        with tempfile.NamedTemporaryFile(prefix=key_type, delete=True) as temp:
            temp_key = temp.name

        command = [
            'ssh-keygen', '-t', key_type, '-f', temp_key, '-N', '', '-q'
        ]
        try:
            self.logger.info('Generating SSH key %s.', key_dest)
            subprocess.check_call(command)
        except subprocess.CalledProcessError:
            self.logger.warning('Could not create SSH key %s.', key_dest)
            return

        shutil.move(temp_key, key_dest)
        shutil.move('%s.pub' % temp_key, '%s.pub' % key_dest)

        file_utils.SetPermissions(key_dest, mode=0o600)
        file_utils.SetPermissions('%s.pub' % key_dest, mode=0o644)
Exemple #2
0
    def _CreateSudoersGroup(self):
        """Create a Linux group for Google added sudo user accounts."""
        if not self._GetGroup(self.google_sudoers_group):
            try:
                command = self.groupadd_cmd.format(
                    group=self.google_sudoers_group)
                subprocess.check_call(command.split(' '))
            except subprocess.CalledProcessError as e:
                self.logger.warning('Could not create the sudoers group. %s.',
                                    str(e))

        if not os.path.exists(self.google_sudoers_file):
            try:
                with open(self.google_sudoers_file, 'w') as group:
                    message = '%{0} ALL=(ALL:ALL) NOPASSWD:ALL'.format(
                        self.google_sudoers_group)
                    group.write(message)
            except IOError as e:
                self.logger.error('Could not write sudoers file. %s. %s',
                                  self.google_sudoers_file, str(e))
                return

        file_utils.SetPermissions(self.google_sudoers_file,
                                  mode=0o440,
                                  uid=0,
                                  gid=0)
Exemple #3
0
    def _CreateSudoersGroup(self):
        """Create a Linux group for Google added sudo user accounts."""
        if not self._GetGroup(self.google_sudoers_group):
            try:
                subprocess.check_call(['groupadd', self.google_sudoers_group])
            except subprocess.CalledProcessError as e:
                self.logger.warning('Could not create the sudoers group. %s.',
                                    str(e))

        with open(self.google_sudoers_file, 'a+') as group:
            """Check if the group is already in the sudoers file"""
            found = False
            message = '%{0} ALL=(ALL:ALL) NOPASSWD:ALL\n'.format(
                self.google_sudoers_group)
            for line in group:
                if message in line:
                    found = True
                    break
            if not found:
                group.write('\n' + message)

        file_utils.SetPermissions(self.google_sudoers_file,
                                  mode=0o440,
                                  uid=0,
                                  gid=0)
    def _GenerateSshKey(self, key_type, key_dest):
        """Generate a new SSH key.

    Args:
      key_type: string, the type of the SSH key.
      key_dest: string, a file location to store the SSH key.

    Returns:
      tuple, key_type and public key string.
    """
        # Create a temporary file to save the created RSA keys.
        with tempfile.NamedTemporaryFile(prefix=key_type, delete=True) as temp:
            temp_key = temp.name

        command = [
            'ssh-keygen', '-t', key_type, '-f', temp_key, '-N', '', '-q'
        ]
        try:
            self.logger.info('Generating SSH key %s.', key_dest)
            subprocess.check_call(command)
        except subprocess.CalledProcessError:
            self.logger.warning('Could not create SSH key %s.', key_dest)
            return

        shutil.move(temp_key, key_dest)
        shutil.move('%s.pub' % temp_key, '%s.pub' % key_dest)

        file_utils.SetPermissions(key_dest, mode=0o600)
        file_utils.SetPermissions('%s.pub' % key_dest, mode=0o644)
        with open('%s.pub' % key_dest, 'r') as pk:
            key_data = pk.read()

        key_values = key_data.split()
        if len(key_values) < 2:
            self.logger.warning('Could not read host key from %s.pub.',
                                key_dest)
            return
        else:
            return key_values[0], key_values[1]
  def SetConfiguredUsers(self, users):
    """Set the list of configured Google user accounts.

    Args:
      users: list, the username strings of the Linux accounts.
    """
    prefix = self.logger.name + '-'
    with tempfile.NamedTemporaryFile(
        mode='w', prefix=prefix, delete=True) as updated_users:
      updated_users_file = updated_users.name
      for user in users:
        updated_users.write(user + '\n')
      updated_users.flush()
      if not os.path.exists(self.google_users_dir):
        os.makedirs(self.google_users_dir)
      shutil.copy(updated_users_file, self.google_users_file)

    file_utils.SetPermissions(self.google_users_file, mode=0o600, uid=0, gid=0)
    def _UpdateAuthorizedKeys(self, user, ssh_keys):
        """Update the authorized keys file for a Linux user with a list of SSH keys.

    Args:
      user: string, the name of the Linux user account.
      ssh_keys: list, the SSH key strings associated with the user.

    Raises:
      IOError, raised when there is an exception updating a file.
      OSError, raised when setting permissions or writing to a read-only
          file system.
    """
        pw_entry = self._GetUser(user)
        if not pw_entry:
            return

        uid = pw_entry.pw_uid
        gid = pw_entry.pw_gid
        home_dir = pw_entry.pw_dir
        ssh_dir = os.path.join(home_dir, '.ssh')
        file_utils.SetPermissions(ssh_dir,
                                  mode=0o700,
                                  uid=uid,
                                  gid=gid,
                                  mkdir=True)

        # Not all sshd's support multiple authorized_keys files so we have to
        # share one with the user. We add each of our entries as follows:
        #  # Added by Google
        #  authorized_key_entry
        authorized_keys_file = os.path.join(ssh_dir, 'authorized_keys')
        prefix = self.logger.name + '-'
        with tempfile.NamedTemporaryFile(mode='w', prefix=prefix,
                                         delete=True) as updated_keys:
            updated_keys_file = updated_keys.name
            if os.path.exists(authorized_keys_file):
                lines = open(authorized_keys_file).readlines()
            else:
                lines = []

            google_lines = set()
            for i, line in enumerate(lines):
                if line.startswith(self.google_comment):
                    google_lines.update([i, i + 1])

            # Write user's authorized key entries.
            for i, line in enumerate(lines):
                if i not in google_lines and line:
                    line += '\n' if not line.endswith('\n') else ''
                    updated_keys.write(line)

            # Write the Google authorized key entries at the end of the file.
            # Each entry is preceded by '# Added by Google'.
            for ssh_key in ssh_keys:
                ssh_key += '\n' if not ssh_key.endswith('\n') else ''
                updated_keys.write('%s\n' % self.google_comment)
                updated_keys.write(ssh_key)

            # Write buffered data to the updated keys file without closing it and
            # update the Linux user's authorized keys file.
            updated_keys.flush()
            shutil.copy(updated_keys_file, authorized_keys_file)

        file_utils.SetPermissions(authorized_keys_file,
                                  mode=0o600,
                                  uid=uid,
                                  gid=gid)
    def testSetPermissions(self, mock_chmod, mock_chown, mock_mkdir,
                           mock_exists, mock_context):
        mocks = mock.Mock()
        mocks.attach_mock(mock_chmod, 'chmod')
        mocks.attach_mock(mock_chown, 'chown')
        mocks.attach_mock(mock_mkdir, 'mkdir')
        mocks.attach_mock(mock_exists, 'exists')
        mocks.attach_mock(mock_context, 'context')
        path = 'path'
        mode = 'mode'
        uid = 'uid'
        gid = 'gid'
        mock_exists.side_effect = [False, True, False]

        # Create a new directory.
        file_utils.SetPermissions(path,
                                  mode=mode,
                                  uid=uid,
                                  gid=gid,
                                  mkdir=True)
        # The path exists, so do not create a new directory.
        file_utils.SetPermissions(path,
                                  mode=mode,
                                  uid=uid,
                                  gid=gid,
                                  mkdir=True)
        # Create a new directory without a mode specified.
        file_utils.SetPermissions(path, uid=uid, gid=gid, mkdir=True)
        # Do not create the path even though it does not exist.
        file_utils.SetPermissions(path,
                                  mode=mode,
                                  uid=uid,
                                  gid=gid,
                                  mkdir=False)
        # Do not set an owner when a UID or GID is not specified.
        file_utils.SetPermissions(path, mode=mode, mkdir=False)
        # Set the SELinux context when no parameters are specified.
        file_utils.SetPermissions(path)
        expected_calls = [
            # Create a new directory.
            mock.call.exists(path),
            mock.call.mkdir(path, mode),
            mock.call.chown(path, uid, gid),
            mock.call.context(path),
            # Attempt to create a new path but reuse existing path.
            mock.call.exists(path),
            mock.call.chmod(path, mode),
            mock.call.chown(path, uid, gid),
            mock.call.context(path),
            # Create a new directory with default mode.
            mock.call.exists(path),
            mock.call.mkdir(path, 0o777),
            mock.call.chown(path, uid, gid),
            mock.call.context(path),
            # Set permissions and owner on an existing path.
            mock.call.chmod(path, mode),
            mock.call.chown(path, uid, gid),
            mock.call.context(path),
            # Set permissions, without changing ownership, of an existing path.
            mock.call.chmod(path, mode),
            mock.call.context(path),
            # Set SELinux context on an existing path.
            mock.call.context(path),
        ]
        self.assertEqual(mocks.mock_calls, expected_calls)