예제 #1
0
    def setUp(self) -> None:
        from consoleme.config import config
        from consoleme.exceptions.exceptions import NoMatchingRequest

        self.NoMatchingRequest = NoMatchingRequest
        auth = get_plugin_by_name(config.get("plugins.auth", "default_auth"))()
        self.Group = auth.Group
예제 #2
0
async def should_auto_approve_policy_v2(extended_request: ExtendedRequestModel,
                                        user, user_groups):
    """
    This uses your fancy internal logic to determine if a request should be auto-approved or not. The default plugin
    set included in ConsoleMe OSS will return False.
    """
    aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
    return await aws.should_auto_approve_policy_v2(extended_request, user,
                                                   user_groups)
예제 #3
0
    async def generate_credential_authorization_mapping(
        self, authorization_mapping: Dict[user_or_group, RoleAuthorizations]
    ) -> Dict[user_or_group, RoleAuthorizations]:
        """This will list accounts that meet the account attribute search criteria."""
        group_mapping = get_plugin_by_name(
            config.get("plugins.group_mapping", "default_group_mapping"))()

        # Generate mapping from internal plugin
        authorization_mapping = (
            await group_mapping.generate_credential_authorization_mapping(
                authorization_mapping))
        # Return mapping
        return authorization_mapping
예제 #4
0
from consoleme.config import config
from consoleme.handlers.base import BaseAPIV1Handler
from consoleme.lib.account_indexers import get_account_id_to_name_mapping
from consoleme.lib.auth import (
    can_admin_policies,
    can_create_roles,
    can_delete_roles,
    can_edit_dynamic_config,
)
from consoleme.lib.generic import get_random_security_logo, is_in_group
from consoleme.lib.plugins import get_plugin_by_name

stats = get_plugin_by_name(config.get("plugins.metrics", "default_metrics"))()
log = config.get_logger()


class UserProfileHandler(BaseAPIV1Handler):
    async def get(self):
        """
        Provide information about site configuration for the frontend
        :return:
        """
        is_contractor = config.config_plugin().is_contractor(self.user)
        site_config = {
            "consoleme_logo": await get_random_security_logo(),
            "google_tracking_uri": config.get("google_analytics.tracking_url"),
            "documentation_url": config.get("documentation_page"),
            "support_contact": config.get("support_contact"),
            "support_chat_url": config.get("support_chat_url"),
            "security_logo": config.get("security_logo.image"),
            "security_url": config.get("security_logo.url"),
예제 #5
0
from consoleme.handlers.v2.templated_resources import TemplatedResourceDetailHandler
from consoleme.handlers.v2.typeahead import (
    ResourceTypeAheadHandlerV2,
    SelfServiceStep1ResourceTypeahead,
)
from consoleme.handlers.v2.user import (
    LoginConfigurationHandler,
    LoginHandler,
    UserManagementHandler,
    UserRegistrationHandler,
)
from consoleme.handlers.v2.user_profile import UserProfileHandler
from consoleme.lib.auth import mk_jwks_validator
from consoleme.lib.plugins import get_plugin_by_name

internal_routes = get_plugin_by_name(
    config.get("plugins.internal_routes", "default_internal_routes"))()

log = config.get_logger()


def make_jwt_validator():
    jwk_url = config.get("sso.jwk_url")
    if not jwk_url:
        raise Exception("Config 'sso.jwk_url' is not defined")
    jwk_set = requests.get(jwk_url).json()
    keys = [k for k in jwk_set["keys"] if k["kty"] == "RSA"]
    jwk_schema = config.get("sso.jwk_schema")
    if not jwk_schema:
        raise Exception("Config 'sso.jwk_schema' is not defined")
    return mk_jwks_validator(keys, jwk_schema["header"], jwk_schema["payload"])
예제 #6
0
import asyncio
import time
from typing import Any

from asgiref.sync import sync_to_async

from consoleme.config import config
from consoleme.exceptions.exceptions import NoMatchingRequest
from consoleme.lib.auth import can_admin_all
from consoleme.lib.cache import store_json_results_in_redis_and_s3
from consoleme.lib.dynamo import UserDynamoHandler
from consoleme.lib.plugins import get_plugin_by_name

auth = get_plugin_by_name(config.get("plugins.auth", "default_auth"))()


async def can_approve_reject_request(user, secondary_approvers, groups):
    # Allow admins to approve and reject all requests
    if can_admin_all(user, groups):
        return True

    if secondary_approvers:
        for g in secondary_approvers:
            if g in groups or g == user:
                return True
    return False


async def can_cancel_request(current_user, requesting_user, groups):
    # Allow the requesting user to cancel their own request
    if current_user == requesting_user:
예제 #7
0
import sys
from datetime import datetime, timedelta

import ujson as json

from consoleme.config import config
from consoleme.exceptions.exceptions import MustBeFte
from consoleme.handlers.base import BaseHandler
from consoleme.lib.account_indexers import get_account_id_to_name_mapping
from consoleme.lib.auth import can_admin_policies
from consoleme.lib.aws import fetch_resource_details
from consoleme.lib.plugins import get_plugin_by_name

log = config.get_logger()
stats = get_plugin_by_name(config.get("plugins.metrics", "default_metrics"))()
aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
group_mapping = get_plugin_by_name(
    config.get("plugins.group_mapping", "default_group_mapping")
)()
auth = get_plugin_by_name(config.get("plugins.auth", "default_auth"))()
internal_policies = get_plugin_by_name(
    config.get("plugins.internal_policies", "default_policies")
)()


class ResourceDetailHandler(BaseHandler):
    async def get(self, account_id, resource_type, region=None, resource_name=None):
        if not self.user:
            return
        if config.get("policy_editor.disallow_contractors", True) and self.contractor:
            if self.user not in config.get(
예제 #8
0
)
from consoleme.lib.account_indexers import get_account_id_to_name_mapping
from consoleme.lib.generic import generate_random_string, iterate_and_format_dict
from consoleme.lib.plugins import get_plugin_by_name
from consoleme.models import (
    ChangeGeneratorModel,
    ChangeGeneratorModelArray,
    ChangeModelArray,
    CrudChangeGeneratorModel,
    InlinePolicyChangeModel,
    PolicyModel,
    ResourceModel,
    Status,
)

group_mapping = get_plugin_by_name(
    config.get("plugins.group_mapping", "default_group_mapping"))()
ALL_ACCOUNTS = None


async def _generate_policy_statement(actions: List, resources: List,
                                     effect: str, condition: Dict) -> Dict:
    """
    Generates an IAM policy resource given actions, effects, resources, and conditions
    :param actions: a List of actions
    :param resources: a List of AWS resource ARNs or wildcards
    :param effect: an Effect (Allow|Deny)
    :return:
    """

    policy_statement = {
        "Action": list(set(actions)),
예제 #9
0
파일: base.py 프로젝트: gleclaire/consoleme
    NoGroupsException,
    NoUserException,
    SilentException,
    WebAuthNError,
)
from consoleme.lib.alb_auth import authenticate_user_by_alb_auth
from consoleme.lib.auth import AuthenticationError
from consoleme.lib.jwt import generate_jwt_token, validate_and_return_jwt_token
from consoleme.lib.oidc import authenticate_user_by_oidc
from consoleme.lib.plugins import get_plugin_by_name
from consoleme.lib.redis import RedisHandler
from consoleme.lib.saml import authenticate_user_by_saml
from consoleme.lib.tracing import ConsoleMeTracer

log = config.get_logger()
stats = get_plugin_by_name(config.get("plugins.metrics", "default_metrics"))()
auth = get_plugin_by_name(config.get("plugins.auth", "default_auth"))()
group_mapping = get_plugin_by_name(
    config.get("plugins.group_mapping", "default_group_mapping"))()


class BaseJSONHandler(tornado.web.RequestHandler):
    # These methods are returned in OPTIONS requests.
    # Default methods can be overridden by setting this variable in child classes.
    allowed_methods = ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"]

    def __init__(self, *args, **kwargs):
        self.jwt_validator = kwargs.pop("jwt_validator", None)
        self.auth_required = kwargs.pop("auth_required", True)
        if self.jwt_validator is None:
            raise TypeError("Missing required keyword arg jwt_validator")
예제 #10
0
import re
from typing import Dict, List, Optional

import ujson as json
from policyuniverse.expander_minimizer import _expand_wildcard_action

from consoleme.config import config
from consoleme.exceptions.exceptions import InvalidRequestParameter, MustBeFte
from consoleme.handlers.base import BaseAPIV1Handler, BaseHandler, BaseMtlsHandler
from consoleme.lib.account_indexers import get_account_id_to_name_mapping
from consoleme.lib.cache import retrieve_json_data_from_redis_or_s3
from consoleme.lib.plugins import get_plugin_by_name
from consoleme.lib.redis import redis_get, redis_hgetall

log = config.get_logger()
stats = get_plugin_by_name(config.get("plugins.metrics", "default_metrics"))()
aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
auth = get_plugin_by_name(config.get("plugins.auth", "default_auth"))()


class AutocompleteHandler(BaseAPIV1Handler):
    async def get(self):
        """
        /api/v1/policyuniverse/autocomplete/?prefix=
        ---
        get:
            description: Supplies autocompleted permissions for the ace code editor.
            responses:
                200:
                    description: Returns a list of the matching permissions.
        """
예제 #11
0
async def get_formatted_policy_changes(account_id, arn, request):
    aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
    existing_role: dict = await aws.fetch_iam_role(account_id,
                                                   arn,
                                                   force_refresh=True)
    policy_changes: list = json.loads(request.get("policy_changes"))
    formatted_policy_changes = []

    # Parse request json and figure out how to present to the page
    for policy_change in policy_changes:
        if not policy_change.get("inline_policies"):
            policy_change["inline_policies"] = []

        if len(policy_change.get("inline_policies")) > 1:
            raise InvalidRequestParameter(
                "Only one inline policy change at a time is currently supported."
            )

        for inline_policy in policy_change.get("inline_policies"):
            if policy_change.get("arn") != arn:
                raise InvalidRequestParameter(
                    "Only one role can be changed in a request")
            policy_name = inline_policy.get("policy_name")
            await validate_policy_name(policy_name)
            policy_document = inline_policy.get("policy_document")
            old_policy = {}
            new_policy: bool = False
            existing_policy_document = {}
            if request.get("status") == "approved":
                old_policy = request.get("old_policy", {})
                if old_policy:
                    existing_policy_document = json.loads(old_policy)[0]
            if not old_policy:
                existing_inline_policies = existing_role["policy"].get(
                    "RolePolicyList", [])
                existing_policy_document = {}
                for existing_policy in existing_inline_policies:
                    if existing_policy["PolicyName"] == policy_name:
                        existing_policy_document = existing_policy[
                            "PolicyDocument"]

            # Generate dictionary with old / new policy documents
            diff = DeepDiff(existing_policy_document, policy_document)

            if not existing_policy_document:
                new_policy = True

            formatted_policy_changes.append({
                "name": policy_name,
                "old": existing_policy_document,
                "new": policy_document,
                "diff": diff,
                "new_policy": new_policy,
            })

        assume_role_policy_document = policy_change.get(
            "assume_role_policy_document")
        if assume_role_policy_document:
            if policy_change.get("arn") != arn:
                raise InvalidRequestParameter(
                    "Only one role can be changed in a request")
            existing_ar_policy = existing_role["policy"][
                "AssumeRolePolicyDocument"]
            old_policy = request.get("old_policy", {})
            if old_policy:
                existing_ar_policy = json.loads(old_policy)[0]

            diff = DeepDiff(
                existing_ar_policy,
                assume_role_policy_document.get("assume_role_policy_document"),
            )

            formatted_policy_changes.append({
                "name":
                "AssumeRolePolicyDocument",
                "old":
                existing_ar_policy,
                "new":
                assume_role_policy_document.get("assume_role_policy_document"),
                "new_policy":
                False,
                "diff":
                diff,
            })

        resource_policy_documents = request.get("resource_policies")
        if resource_policy_documents:
            for resource in resource_policy_documents:
                existing_policy_document = None
                # TODO: make this actually fetch the resource policy
                # existing_policy_document = aws.fetch_resource_policy()
                new_policy_document = resource["policy_document"]
                diff = DeepDiff(existing_policy_document, new_policy_document)

                formatted_policy_changes.append({
                    "name": "ResourcePolicy",
                    "old": existing_policy_document,
                    "new": new_policy_document,
                    "new_policy": not existing_policy_document,
                    "diff": diff,
                })
    return {"changes": formatted_policy_changes, "role": existing_role}
예제 #12
0
from threading import Timer
from typing import Any, Dict, List, Optional, Union

import logmatic
import ujson as json
import yaml
from asgiref.sync import async_to_sync
from pytz import timezone

from consoleme.lib.aws_secret_manager import get_aws_secret
from consoleme.lib.plugins import get_plugin_by_name

config_plugin_entrypoint = os.environ.get(
    "CONSOLEME_CONFIG_ENTRYPOINT", "default_config"
)
config_plugin = get_plugin_by_name(config_plugin_entrypoint)


def dict_merge(dct: dict, merge_dct: dict):
    """Recursively merge two dictionaries, including nested dicts"""
    for k, v in merge_dct.items():
        if (
            k in dct
            and isinstance(dct[k], dict)
            and isinstance(merge_dct[k], collections.Mapping)
        ):
            dict_merge(dct[k], merge_dct[k])
        else:
            # Prefer original dict values over merged dict values if they already exist
            if k not in dct.keys():
                dct[k] = merge_dct[k]
예제 #13
0
async def should_auto_approve_policy(events, user, user_groups):
    aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
    result = await aws.should_auto_approve_policy(events, user, user_groups)
    return result
예제 #14
0
from typing import Any, Dict

import sentry_sdk
import ujson as json
from asgiref.sync import sync_to_async
from cloudaux.aws.sts import boto3_cached_conn

from consoleme.config import config
from consoleme.exceptions.exceptions import (
    DataNotRetrievable,
    MissingConfigurationValue,
)
from consoleme.lib.dynamo import UserDynamoHandler
from consoleme.lib.plugins import get_plugin_by_name

aws = get_plugin_by_name(config.get("plugins.aws", "default_aws"))()
log = config.get_logger()


async def get_resource_from_cloudtrail_deny(ct_event, raw_ct_event):
    """
    Naive attempt to determine resource from Access Deny CloudTrail event. If we can't parse it from the
    Cloudtrail message, we return `*`.
    """

    resources = [
        resource["ARN"] for resource in raw_ct_event.get("resources", [])
        if "ARN" in resource
    ]
    if resources:
        resource: str = max(resources, key=len)