def __init__(self, kms_key_arn, s3_bucket, role): self.iam = IAM(boto3) self.iam.update_iam_roles(s3_bucket, kms_key_arn, IAMUpdater.role_policies) self.iam_target_account = IAM(role) self.iam_target_account.update_iam_target_account_roles( kms_key_arn, IAMUpdater.target_role_policies)
def get_iam_client(): app_code = env.BKAPP_SOPS_IAM_APP_CODE app_secret = env.BKAPP_SOPS_IAM_APP_SECRET_KEY if settings.BK_IAM_SKIP: return DummyIAM(app_code, app_secret, settings.BK_IAM_INNER_HOST, settings.BK_PAAS_ESB_HOST) if settings.BK_IAM_APIGW_HOST: return IAM(app_code, app_secret, bk_apigateway_url=settings.BK_IAM_APIGW_HOST) return IAM(app_code, app_secret, settings.BK_IAM_INNER_HOST, settings.BK_PAAS_ESB_HOST)
def update_iam(role, s3_buckets, kms_key_arns, role_policies): iam = IAM(role.client("iam")) iam.update_iam_roles( s3_buckets, kms_key_arns, role_policies )
class ApplyURLGenerator: iam = IAM( settings.APP_CODE, settings.SECRET_KEY, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST, settings.BK_IAM_APIGATEWAY_URL, ) @classmethod def generate_apply_url( cls, username: str, action_request_list: List[ActionResourcesRequest]) -> str: """ 生成权限申请跳转 url 参考 https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#14-获取无权限申请跳转url """ app = cls._make_application(action_request_list) ok, message, url = cls.iam.get_apply_url(app, bk_username=username) if not ok: logger.error('generate_apply_url failed: %s', message) return settings.BK_IAM_APP_URL return url @staticmethod def _make_application( action_request_list: List[ActionResourcesRequest] ) -> models.Application: """为 generate_apply_url 方法生成 models.Application""" return models.Application( settings.BK_IAM_SYSTEM_ID, actions=[req.to_action() for req in action_request_list])
def update_iam(role, s3_bucket, kms_key_arn, role_policies): iam = IAM(role) iam.update_iam_roles( s3_bucket, kms_key_arn, role_policies )
def authenticate_credentials(self, userid, password): if userid != "bk_iam": raise AuthenticationFailed("username is not bk_iam") iam = IAM(settings.APP_ID, settings.APP_TOKEN, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST) ok, msg, token = iam.get_token(settings.APP_ID) if not ok: raise AuthenticationFailed(f"get system token fail: {msg}") if password != token: raise AuthenticationFailed("password in basic_auth not equals to system token") return (FancyDict(username=userid, password=password), None)
def authenticate_credentials(self, userid: str, password: str, request=None): if userid != "bk_iam": raise AuthenticationFailed("username is not bk_iam") iam = IAM( settings.APP_CODE, settings.SECRET_KEY, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST, settings.BK_IAM_APIGATEWAY_URL, ) ok, msg, token = iam.get_token(settings.BK_IAM_SYSTEM_ID) if not ok: raise AuthenticationFailed(f"get system token fail: {msg}") if password != token: raise AuthenticationFailed( "password in basic_auth not equals to system token") return (FancyDict(username=userid, password=password), None)
class ProjectFilter: """ 项目权限过滤器. note: 用于查询用户具有 project_view 权限的所有项目(iam v3 本身不支持这种查询) """ iam = IAM( settings.APP_CODE, settings.SECRET_KEY, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST, settings.BK_IAM_APIGATEWAY_URL, ) def make_view_perm_filter(self, username: str) -> Dict: request = Request( settings.BK_IAM_SYSTEM_ID, Subject('user', username), Action(ProjectAction.VIEW), None, None, ) policies = self._do_policy_query(request) if not policies: return {} return self._make_dict_filter(policies) @staticmethod def op_is_any(dict_filter: Dict[str, List[str]]) -> bool: if not dict_filter: return False if dict_filter.get('op') == OP.ANY: return True return False def _do_policy_query(self, request) -> Optional[Dict]: # 1. validate if not isinstance(request, Request): raise AuthInvalidRequest( 'request should be instance of iam.auth.models.Request') request.validate() # 2. _client.policy_query policies = self.iam._do_policy_query(request) # the polices maybe none if not policies: return None return policies @staticmethod def _make_dict_filter(policies: Dict) -> Dict: """ 基于策略规则, 生成 project_id 过滤器 :param policies: 权限中心返回的策略规则, 如 {'op': OP.IN, 'value': [2, 1], 'field': 'project.id'} :return: project_id 过滤器, 如 {'value': [1, 2], 'op': OP.IN} """ op = policies['op'] if op not in [OP.IN, OP.EQ, OP.ANY, OP.OR, OP.AND]: raise AuthInvalidRequest( f'make_dict_filter does not support op:{op}') if op == OP.EQ: return {'value': [policies['value']], 'op': OP.IN} if op in [OP.IN, OP.ANY]: return {'value': policies['value'] or [], 'op': op} # 如果 op 是 OP.OR 或 OP.AND,只处理一级,不考虑嵌套的情况 value_list = [] for policy in policies['content']: if policy['field'] != 'project.id': continue op = policy['op'] if op == OP.ANY: return {'value': policy['value'] or [], 'op': op} value = policy['value'] if op == OP.IN: value_list.extend(value) elif op == OP.EQ: value_list.append(value) return {'value': list(set(value_list)), 'op': OP.IN}
class IAMClient: """提供基础的 iam client 方法封装""" iam = IAM(settings.APP_ID, settings.APP_TOKEN, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST) def resource_type_allowed(self, username: str, action_id: str, use_cache: bool = False) -> bool: """ 判断用户是否具备某个操作的权限 note: 权限判断与资源实例无关,如创建某资源 """ request = self._make_request(username, action_id) if not use_cache: return self.iam.is_allowed(request) return self.iam.is_allowed_with_cache(request) def resource_inst_allowed(self, username: str, action_id: str, res_request: ResourceRequest, use_cache: bool = False) -> bool: """ 判断用户对某个资源实例是否具有指定操作的权限 note: 权限判断与资源实例有关,如更新某个具体资源 """ request = self._make_request(username, action_id, resources=res_request.make_resources()) if not use_cache: return self.iam.is_allowed(request) return self.iam.is_allowed_with_cache(request) def resource_type_multi_actions_allowed( self, username: str, action_ids: List[str]) -> Dict[str, bool]: """ 判断用户是否具备多个操作的权限 note: 权限判断与资源实例无关,如创建某资源 :returns 示例 {'project_create': True} """ return { action_id: self.resource_type_allowed(username, action_id) for action_id in action_ids } def resource_inst_multi_actions_allowed( self, username: str, action_ids: List[str], res_request: ResourceRequest) -> Dict[str, bool]: """ 判断用户对某个资源实例是否具有多个操作的权限. note: 权限判断与资源实例有关,如更新某个具体资源 :return 示例 {'project_view': True, 'project_edit': False} """ actions = [Action(action_id) for action_id in action_ids] request = MultiActionRequest(settings.APP_ID, Subject("user", username), actions, res_request.make_resources(), None) return self.iam.resource_multi_actions_allowed(request) def batch_resource_multi_actions_allowed( self, username: str, action_ids: List[str], res_request: ResourceRequest) -> Dict[str, Dict[str, bool]]: """ 判断用户对某些资源是否具有多个指定操作的权限 note: 当前sdk仅支持同类型的资源 :return 示例 {'0ad86c25363f4ef8adcb7ac67a483837': {'project_view': True, 'project_edit': False}} """ actions = [Action(action_id) for action_id in action_ids] request = MultiActionRequest(settings.APP_ID, Subject("user", username), actions, [], None) resources_list = [[res] for res in res_request.make_resources()] return self.iam.batch_resource_multi_actions_allowed( request, resources_list) def _make_request(self, username: str, action_id: str, resources: Optional[List[Resource]] = None) -> Request: return Request( settings.APP_ID, Subject("user", username), Action(action_id), resources, None, ) def _grant_resource_creator_actions(self, username: str, data: Dict): """ 用于创建资源时,注册用户对该资源的关联操作权限. note: 具体的关联操作见权限模型的 resource_creator_actions 字段 """ return self.iam._client.grant_resource_creator_actions( None, username, data)
class IAMClient: """提供基础的 iam client 方法封装""" iam = IAM( settings.APP_CODE, settings.SECRET_KEY, settings.BK_IAM_HOST, settings.BK_PAAS_INNER_HOST, settings.BK_IAM_APIGATEWAY_URL, ) def resource_type_allowed(self, username: str, action_id: str, use_cache: bool = False) -> bool: """ 判断用户是否具备某个操作的权限 note: 权限判断与资源实例无关,如创建某资源 """ request = self._make_request(username, action_id) if not use_cache: return self.iam.is_allowed(request) return self.iam.is_allowed_with_cache(request) def resource_inst_allowed( self, username: str, action_id: str, resources: List[Resource], use_cache: bool = False ) -> bool: """ 判断用户对某个资源实例是否具有指定操作的权限 note: 权限判断与资源实例有关,如更新某个具体资源 """ request = self._make_request(username, action_id, resources=resources) if not use_cache: return self.iam.is_allowed(request) return self.iam.is_allowed_with_cache(request) def resource_type_multi_actions_allowed(self, username: str, action_ids: List[str]) -> Dict[str, bool]: """ 判断用户是否具备多个操作的权限 note: 权限判断与资源实例无关,如创建某资源 :returns 示例 {'project_create': True} """ return {action_id: self.resource_type_allowed(username, action_id) for action_id in action_ids} def resource_inst_multi_actions_allowed( self, username: str, action_ids: List[str], resources: List[Resource] ) -> Dict[str, bool]: """ 判断用户对某个(单个)资源实例是否具有多个操作的权限. note: 权限判断与资源实例有关,如更新某个具体资源 :return 示例 {'project_view': True, 'project_edit': False} """ actions = [Action(action_id) for action_id in action_ids] request = MultiActionRequest(settings.BK_IAM_SYSTEM_ID, Subject("user", username), actions, resources, None) return self.iam.resource_multi_actions_allowed(request) def batch_resource_multi_actions_allowed( self, username: str, action_ids: List[str], resources: List[Resource] ) -> Dict[str, Dict[str, bool]]: """ 判断用户对某些资源是否具有多个指定操作的权限. 当前sdk仅支持同类型的资源 :return 示例 {'0ad86c25363f4ef8adcb7ac67a483837': {'project_view': True, 'project_edit': False}} """ actions = [Action(action_id) for action_id in action_ids] request = MultiActionRequest(settings.BK_IAM_SYSTEM_ID, Subject("user", username), actions, [], None) resources_list = [[res] for res in resources] return self.iam.batch_resource_multi_actions_allowed(request, resources_list) def _make_request(self, username: str, action_id: str, resources: Optional[List[Resource]] = None) -> Request: return Request( settings.BK_IAM_SYSTEM_ID, Subject("user", username), Action(action_id), resources, None, )
def __init__(self, app_name, image, user_data_file, task_definition=None, service=None, desired_count=1, max_health=None, min_health=None, container_definitions=None, key_name=None, security_groups=None, user_data=None, lambda_role=None, aws_parameters=None): ''' :type user_data_file: string :param user_data_file: path a .txt file containing bash commands to be executed on an EC2 instance at launch time. At least, the commands must set the following parameters: `ECS_CLUSTER` and {"auths": { `dkr.ecr.region.awsamazon.com`: { "auth": `auth_tocken` } "https://index.docker.io/v1/": { "auth": `auth_token` } } must be set in the following file: /etc/ecs/ecs.config in the EC2 instance. See the AWS documentation for further information: ##############################URL. :type max_health: int :param max_health: maximumPercent for the deployment configuration of an ECS service. Default value in the AWS API is 200. :type min_health: int :param min_health: minimumHealthyPercent for the deployment configuration of an ECS service. Default value in the AWS API is 50. :type key_name: string :param key_name: name of the ssh key pair to be used when creating EC2 instances within the cluster.b ''' self.app_name = app_name # The following parameters are automatically assigned # based on the name of the application following a # default naming structure. This is to ensure that we # follow a systematic and ordered approachto naming our # resources that makes it easier to identify and locate # them. # Users are free to modify these attributes by repointing # them to different strings. This might be warranted in # cases in which some flexibility is required. For this # reason, the attributes are not readonly. # Users who modify these attributes are responsible for # keeping track of the resources they create associated # with the cluster. self.cluster_name = app_name + '_cluster' self.service_name = app_name + '_service' self.task_name = app_name + '_task' if container_definitions is None: self.container_definitions = [] else: self.container_definitions = container_definitions self.task_definition = task_definition self.service = service self.image = image self.desired_count = desired_count self.min_health = min_health self.max_health = max_health self.key_name = key_name self.user_data_file = user_data_file self.user_data = user_data self.security_groups = security_groups self._instances = [] self.lambda_role = lambda_role #self.default_lambda_role = 'lambda_ecs_role' self.aws_parameters = aws_parameters self._make_clients() ## Allow passing aws connection parameters to get ## the connections. self.ec2 = EC2Instance(None, None, None) self.iam = IAM() self.sns = SNS() self.awslambda = Lambda() self._cluster = None
def cls(): cls = IAM(boto3) cls.client = Mock() cls.client.get_role_policy.return_value = stub_iam.get_role_policy cls._fetch_policy_document('some_role_name', 'some_policy_name') return cls
if __name__ == "__main__": # eval print("\nTHE EVAL EXAMPLE:\n") eval_exmaple() print_spearator() # convert to sql / django queryset print("\nTHE CONVERT EXAMPLE:\n") convert_example() # make a request print_spearator() subject = Subject("user", "admin") # action = Action("edit_app") # action = Action("access_developer_center") action = Action("develop_app") resource = Resource("bk_paas", "app", "bk_test", {}) request = Request("bk_paas", subject, action, [resource], None) print("the request: ", request.to_dict()) iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", "http://127.0.0.1:8080", "https://{PAAS_DOMAIN}") # recommend if got an APIGateway # iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", bk_apigateway_url="http://{IAM_APIGATEWAY_URL}") print("is_allowed: ", iam.is_allowed(request)) print("query: ", iam.make_filter(request))
def insert_mockdata(): src = Path(get_source_dir()) / 'data' / 'mock_data.yaml' if not src.exists(): raise FileNotFoundError( 'You need a mock_data.yaml placed under the data/ folder.') with open(src) as f: data = yaml.load(f) # Log into IAM as ERP envyaml_path = Path(get_source_dir()) / 'data/envs/env.yaml' with open(envyaml_path) as f: envs = yaml.load(f) appid = envs['appids']['erp'] iam = IAM("http://localhost:15002", appid, None, str(Path(get_source_dir()) / 'data/keys/erp.pem')) backplane = Backplane('http://localhost:15003') for user in data.get('users', {}).values(): try: user_id = iam.user_register(user['name'], user['email'], user['password'])['result'] user['user_id'] = user_id # Now it's a user. We'll start promoting it to other roles. if user.get('role') in ['dev', 'member', 'admin']: iam.set_user_profile(user_id, role='dev') if user.get('role') in ['member', 'admin']: iam.set_user_profile(user_id, role='member') if user.get('role') in ['admin']: iam.set_user_profile(user_id, role='admin') except HTTPError as e: if e.response.status_code == 403: print('\n-!> Skipping user [%s]: exists' % user['name']) for lcodename, lifecycle in data.get('devcats').items(): # First we check if that is actually there lcfound = False try: lcfound = bool(DeviceLifecycle(backplane).get(lcodename)) except: pass if lcfound: print('\n-!> Skipping lifecycle [%s]: exists' % lcodename) continue try: lifecycle['codename'] = lcodename lifecycle['status'] = 'SUPPORTED' l = DeviceLifecycle(backplane, True, **lifecycle) l.save() except Exception as e: print('\n-!> Failed to create lifecycle [%s]: %s' % (lcodename, e)) for appcat_id, appcat in data.get('appcats').items(): # First we check if that is actually there found = False try: found = bool(AppCat(backplane).get(appcat_id)) except: pass if found: print('\n-!> Skipping appcat [%s]: exists' % appcat_id) continue try: appcat['_id'] = appcat_id a = AppCat(backplane, True, **appcat) a.save() except Exception as e: print('\n-!> Failed to create appcat [%s]: %s' % (lcodename, e)) raise sites = {s.name: s._id for s in Site(backplane).list()} for site_name, site in data.get('sites', {}).items(): # First we check if the site is actually there if site_name in sites: print('\n-!> Skipping site [%s]: exists' % site_name) site['site_id'] = sites[site_name] continue try: # Substitude the owner id owner = site.pop('owner', None) if owner: site['owner_id'] = data.get('users', {}).get(owner, {}).get('user_id') site['name'] = site_name s = Site(backplane, True, **site) s.save() site['site_id'] = s._id except Exception as e: print('\n-!> Failed to create site [%s]: %s' % (site_name, e)) for device_id, node in data.get('nodes', {}).items(): # First we check if the node is actually there if Node(backplane).list(device_id=device_id): print('\n-!> Skipping node [%s]: exists' % hex(device_id)) continue try: node['owner_id'] = None node['site_id'] = None # Substitude the owner id owner = node.pop('owner', None) if owner: node['owner_id'] = data.get('users', {}).get(owner, {}).get('user_id') # Substitude the site id site = node.pop('site', None) if site: node['site_id'] = data.get('sites', {}).get(site, {}).get('site_id') node['device_id'] = device_id n = Node(backplane, True, **node) n.save() node['node_id'] = n._id except Exception as e: print('\n-!> Failed to create node [%s]: %s' % (hex(device_id), e)) for device_id, router in data.get('routers', {}).items(): # First we check if the router is actually there if Router(backplane).list(device_id=device_id): print('\n-!> Skipping router [%s]: exists' % hex(device_id)) continue try: router['owner_id'] = None # Substitude the owner id owner = router.pop('owner', None) if owner: router['owner_id'] = data.get('users', {}).get(owner, {}).get('user_id') router['device_id'] = device_id n = Router(backplane, True, **router) n.save() router['router_id'] = n._id except Exception as e: print('\n-!> Failed to create router [%s]: %s' % (hex(device_id), e)) dest = Path(get_source_dir()) / 'data' / 'mock_data.results.yaml' with open(dest, 'w') as fp: yaml.dump(data, fp)
from logger import Logger from iam import IAM from cloudformation import Cloudformation logger = Logger(loglevel='info') iam = IAM(logger, region='us-west-2') cf = Cloudformation(logger, region='us-west-2') RoleName='' cfoutput = cf.describe_stack('') for keys in cfoutput['Stacks'][0]['Outputs']: if keys['OutputKey'] == 'InstanceRoleARN': iam_role_arn = keys['OutputValue'] role = "" role_name = role.split("/")[-1] logger.info(role_name) role_info = iam.list_role_policies(RoleName=RoleName) if 'ASG-Policy-For-Worker' in role_info: logger.info('found role') iam.delete_role_policy( RoleName=RoleName )